Apparently talking about DOS Extenders is too hot for Twitter: AKA Phar Lap 386

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, if it was even worth the effort of doing WIP’s as I didn’t want to make it super annoying.

I logged on to post a fun update that I’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.

Talking about DOS Extenders is spammy and manipulation!

I don’t get what triggered it, but oh well there was a ‘have a review’ and yeah that was fine. Great. So I’m unlocked so I go ahead and post with the forbidden topic, as I’m clearly dumb, and forgetting that Twitter is for hate mobs & posting pictures of food, and cat pictures.

The Sairen AGI interpreter built with Watcom 386/7.0 & Phar Lap 386 4.1

So yes, that was a line too far, and now that’s it.

Now some of you may think, if you buy ‘the plan’ you’ll no doubt be exempt from the heavy hands of Twitter

3 squids a month

But I already was and had been for a while.

Your account is suspended

So that’s the end of that. I guess it’s all too confusing for a boomer like me.

Cancel me, cancel you

So needless to say I cancelled Twitter as well. Kind of sneaky they didn’t auto-cancel taking money.

So yeah, with that out of the way, let’s continue into DOS Extender land. I added just enough 386 magic, onto github: neozeed/sarien286. Yes I see now it really was a poorly named repo. Such is life.

There is 3 main things for porting old programs where they take care of all the logic, it’s going to be File I/O, Screen I/O, and timers. Luckily this time it was easier than I recalled.

Over on usenet (google groups link) Chris Giese shared this great summary on direct memory access from various methods:

/* 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 <dos.h> /* 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 <dos.h> /* MK_FP() */
int main(void) {
char far *screen = (char far *)MK_FP(0xA000, 0);
initMode13();
*screen = 1;
return 0;
}

It is missing the Phar Lap 286 method:

/* Get PM pointer to text screen */
  DosMapRealSeg(0xb800,4000,&rseg);
  textptr=MAKEP(rseg,0);

But it’s very useful to have around as documentation is scarce.

Which brings me to this (again?)

Phar Lap 386|Dos-Extender 4.1

Years ago, I had managed to score a documentation set, and a CD-ROM with a burnt installed copy of the extender. I didn’t know if it was complete, but of course these things are so incredibly rare I jumped on the chance to get it!

2011!

Unfortunately, I didn’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 *years* later and Foone uploaded a document set on archive.org. GREAT! As far as I can tell the only difference in what I had is that I’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 Phar Lap TNT 6.0 that I had also managed to acquire.

Although unlocking the video RAM wasn’t too bad, once I knew what to do, the other thing is to hook the clock for a timer. ISR’s are always hell, but at least this is a very simple one:

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 );
  }

The methodology is almost always the same, as always, it’s the particular incantation.

So yeah, it’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’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 fileglob.c file but it now builds and links fine.

Another thing to do differently when using Watcom 7, is that it doesn’t include a linker, rather you need to use 386LINK. Generating the response file, as there is so many objects didn’t turn out too hard once I realized that by default everything is treated as an object.

Another fun thing is that you can tell the linker to use the program ‘stub386.exe’ so that it will run ‘run386’ on it’s own, making your program feel more standalone. From the documentation:

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.

So that means I can just use the following as my linker response file.

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

It really was that simple. I have to say it’s almost shocking how well this went.

So, this brings me back, full circle to where it started, me getting banned for posting this:

32bit!

I thought it was exciting!

For anyone who feels like trying it, I prepped a 5 1/4″ floppy disk image.

running on 86box, 386DX-40 CGA graphics

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.

16bit on the left, 32bit on the right.

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

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’s the 1970s.

Phar Lap’s 286/DOS-Extender: why nobody used it for games

Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.

-Ian Malcolm

Ever since I got my first 286 board way back in the early 90’s (1990? 1991?) I have been intrigued by the whole protected mode of operation. Unfortunately, in the era the required tools were way out of my reach, and of course were not available at retail. But now I live in the future where I have all the parts! Let’s look at the needed parts

I have to once more again thank my patrons, and people tolerating the google ads as it made all the difference in being able to buy all this stuff. And now is as good a time as any other to put it all together.

I stumbled upon this repo on sourceforge, Sarien. It included a Turbo C++ port, which is pretty exciting! So, this became my goal, get Sarien running on Phar Lap 286.

Installing Microsoft C 6.0a

Installing Microsoft C requires you to pick and choose both hosting, targeting environments, along with what the preferred libraries are. In the business we call this foreshadowing as this can be such a giant PITA. At least virtual machines are fast, plentiful, and cheap. In addition I had been using MS-DOS player to host the tools on Windows 11. This of course proved weird later.

The first step was getting it running on MS-DOS using Microsoft C 6.0a. This was actually pretty easy, the hard part was working out the makefile, as some files don’t compile with optimisations. And overall, the project doesn’t seem to work with /Ox at all. I haven’t spent enough time mixing and matching settings to find what actually doesn’t work, but I’m in a hurry, and /Os seems to work just fine.

In no time I had both the CGA & VGA drivers up and running and verified working on my PS/2. Great!

Now comes the fun, getting it ready to run on Pharlap.

The magic!

Phar Lap’s 286|DOS-Extender is pure magic. A DOS extender is a special program that can load a protected mode program into memory on a 286 or better computer and run it. At it’s heart, it can proxy MS-DOS functionality from protected mode to real mode, allowing you to use a lot of methodology and code from traditional real mode code. Phar Lap, goes beyond that by providing a pseudo OS/2 1.2 environment on MS-DOS, including advanced features like DLL’s, and being able to use ALL the RAM in your computer. Of course on the 286 there is a massive caveat:

The 286 has no built-in function for switching from protected mode to real mode. This makes programs that rely a LOT on MS-DOS potentially very slow. You can absolutely feel the difference between the real mode and the protected mode version of Sarien.

Phar Lap does include a test program, swtest which can benchmark the switching methods, so let’s run it and get some scores.

Switch code version = 1.14
BIOS signature: BA66CC86
BIOS date: 02/13/87

Machine ID = 0, A20 method = PS2, Reset method = Standard
Starting test for Switch Mode 3 (SLOW) ... Test complete.
Avg switch time (usecs): To prot = 34, To real = 101, Total = 135
Min switch time (usecs): To prot = 32, To real = 98, Total = 130
Max switch time (usecs): To prot = 35, To real = 103, Total = 138

Machine ID = 0, A20 method = PS2, Reset method = Standard
Starting test for Switch Mode 2 (AT) ... Test complete.
Avg switch time (usecs): To prot = 34, To real = 86, Total = 120
Min switch time (usecs): To prot = 33, To real = 83, Total = 116
Max switch time (usecs): To prot = 36, To real = 88, Total = 124

Machine ID = 0, A20 method = PS2, Reset method = Standard
Starting test for Switch Mode 1 (SURE) ... Test complete.
Avg switch time (usecs): To prot = 34, To real = 70, Total = 104
Min switch time (usecs): To prot = 32, To real = 68, Total = 100
Max switch time (usecs): To prot = 35, To real = 72, Total = 107

For those of you wondering what the timing is like on a 386, here is my 16Mhz PS/2 Model 80 board (now with fully 32bit memory)

Switch code version = 1.14
BIOS signature: 039D2DB4
BIOS date: 03/30/87

Machine ID = 0, A20 method = PS2, Reset method = Standard
Starting test for Switch Mode 5 (386) ... Test complete.
Avg switch time (usecs): To prot = 31, To real = 22, Total = 53
Min switch time (usecs): To prot = 30, To real = 20, Total = 50
Max switch time (usecs): To prot = 32, To real = 23, Total = 55

I’m honestly surprised the 286 switches from protected back to real so quickly! Although as you can see from the 386 timings it’s significantly faster than the 286.

Here is a quick video, real mode on the left, protected mode on the right. Yes I need to get a VGA capture card. Sorry.

Real mode on the left, Protected on the right. Running on the 386

Being a DOS extender it does have built in functions for things like hooking interrupts like this:

    /* install our new timer tick routine */
    DosSetPassToProtVec(IRQ0, (PIHANDLER)new_prot_timer_tick,
        &old_prot_timer_tick, &old_real_timer_tick);

Unlike some kind of OS/2 method which would involve creating a thread and or timers.

Setting video modes via the video BIOS is also supported, using the built in int86 style calls:

    memset(&r,0x0,sizeof(r));
    r.h.ah = 0;
    r.h.al = 3;
    int86(0x10, &r, &r);

Using pointers into things like video ram do require ‘asking for permission’ but it’s not too involved:

    int rseg;
  /* Get PM pointer to text screen */
    DosMapRealSeg(0xb800,4000,&rseg);
    textptr=MAKEP(rseg,0);

with the segment mapped, and a pointer to the segment, and now I can read/write directly into video RAM!

  /* save text screen */
    memcpy(textbuf,textptr,4000);

Just like that!

I’m not sure what I screwed up on the VGA graphics, as it doesn’t work correctly, but oddly enough CGA does work.

And now this is where everything goes off the rails.

Sairen running on Qemu & DOSbox

It ran fine on emulation. So all excited I fired up the PS/2 and….

General protection fault

This lead me to more fun in how on earth to debug this. Of course Phar Lap 286 version 2.5 requires me to have Microsoft C/C++ 7.0. I shamelessly downloaded a disk set from pcjs.org. You actually need to install it, to copy out the files required:

  • 28/05/1991 05:37 pm 47,216 CFIG286.EXE
  • 26/11/1991 11:19 am 13,531 GORUN286.EXE
  • 19/03/1992 04:00 am 42,720 shw0.dll
  • 19/03/1992 04:00 am 105,039 eew0cxx.dll
  • 19/03/1992 04:00 am 410,112 cvw4.exe
  • 19/03/1992 04:00 am 91,118 eew0can.dll
  • 19/03/1992 04:00 am 74,400 emw0w0.dll
  • 03/08/1992 09:34 pm 2,649 INT33.DLL
  • 03/08/1992 09:40 pm 2,718 MSG.DLL
  • 03/08/1992 09:40 pm 1,702 NAMPIPES.DLL
  • 03/08/1992 09:42 pm 2,073 NLS.DLL
  • 03/08/1992 09:43 pm 5,184 PTRACE.DLL
  • 03/08/1992 09:45 pm 2,320 SESMGR.DLL
  • 03/08/1992 09:50 pm 1,508 WIN87EM.DLL
  • 05/08/1992 12:04 am 3,100 KEYBOARD.DLL
  • 05/08/1992 06:33 pm 270 TOOLHELP.DLL
  • 14/08/1992 07:38 pm 7,891 KERNEL.DLL
  • 14/08/1992 09:40 pm 14,545 USER.DLL
  • 09/09/1992 10:59 pm 209,922 RUN286.EXE
  • 09/09/1992 10:59 pm 229,046 RUN286D.EXE
  • 14/09/1992 11:01 pm 14,024 TLW0LOC.DLL
  • 17/09/1992 07:26 pm 34,152 CVP7.EXE

While CVP7 does come with Phar Lap, you have to run it via run286. As you may have noticed there is a mixture of OS/2 and Windows DLL’s in here, as at this point CodeView was a Windows protected mode debugger. The divorce was in full swing, and Microsoft C/C++ 7.0 had amputated the majority of OS/2 support. I’m sure all this is in the manuals, however all I have is disk images. There was no C 6.0a supported hosted debugger. Maybe it’s in the v1/v2 of Phar Lap 286, but I only have 2.5. There is version 3 files on the internet but I wanted to stick to 2.5.

Exception #13

And this is all I got. Yes, I did recompile with ‘/Od /Zi’ along with using cvpack on the executable. Yes, after copying the source to the PS/2 I was able to see the source line mapping, but it immediately jumps to assembly and GP Faults. All this is fine, but IT RUNS UNDER EMULATION.

What is going on?!

I asked around on discord, and found someone willing to test on their 286. It also crashed. I tried VMware and .. it crashed too! So did 86box! Ok now we’re going somewhere!

Since I had been using MS-DOS player to run the tools, I had an issue with the linker in C 6.0a crashing, so I tried the one from C/C++ 7. It also didn’t work. I tried the one from Visual C++ 1.5. It also failed. Almost giving up on the entire thing, since I had copied the source code to the PS/2, I tried something really silly, I compiled it using the /qc or QuickC flag. I wasn’t too worried about sizes as again I’m going to run in protected mode. It took some 20-30 minutes to compile, as 10Mhz machines are not the best for building software in this modern age. Much to my surprise it actually ran.

First run!

This was kind of shocking as I’m not sure what I screwed up to not get this to work, but it worked! I went ahead and changed the build to not use QuickC, but rebuild with /Os (Optimize for space). It took about an hour. And it too worked.

Phar Lap 286 running on OS/2 2.00 on VMware

Shockingly it runs! I’m not sure what on earth is up with the linking. I did find it easier to just rebuild on Qemu since it can easily map into my source directory and copy everything over and re-build very quickly.

Later I did try copying over compiled objects built using the MS-DOS Player, and linked them natively, and they ran fine.

What is it with the LINK?!

It all fits! Stacker rules!

One weird thing on 86box is my pre-built machine I was using has a 5 1/4″ 1.2Mb floppy for the A: drive. It’s too small to fit MS-DOS, the game data and Phar Lap 286 all on there. Although Stacker to the rescue and it fits!

It can save and even load those saves!

I removed a lot of Unix quality of life, to make it more MS-DOS dumping everything in the same directory so you can save & load games.

Assuming anyone is interested in this at all, I have the source up on github. I’ll follow up with some performance videos showing how much slower real vs protected mode is, along with some binaries/demos. A 5 1/4″ floppy disk image can be downloaded here for any suitable emulator.

Too many hard disks? The smiley face boot crash

smiley face crash
☺on boot

I’d never seen this one before, but attempting to boot up PC-DOS 4.00 or 4.01 on my PS/2 model 60, with 7 virtual disks attached, all I get is a single smiley/happy face, ASCII 1 ‘☺’ on boot.

MS-DOS 5.00 doesn’t care.

all my SCSI virtual disks
too many disks!

While trying the Apricot MS-DOS 4 set I got on eBay, it boots from floppy disks, crashes trying to boot from the hard disk, and trying to run fdisk just causes a divide by zero error.

run-time error R6003
- integer divide by 0
– integer divide by 0
run-time error R6003
- integer divide by 0

I’m a bit reluctant to rip the whole machine apart as SD card extension cables don’t work for me which is even more annoying. Didn’t people buy big machines and put in a LOT of disks to just run MS-DOS? Even a Netware server still requires MS-DOS to boot.

Is my 286 just too weird?!

I’m not sure if it’s worth following up, but it is perplexing. Maybe I need to rename all my disks, and stick with whatever was actually selling in 1987. And sadly that means not fully loading it out.

Check out Julio Merino’s article on real mode memory allocation:

From 0 to 1 MB in DOS

https://blogsystem5.substack.com/p/from-0-to-1-mb-in-dos

I’m looking forward to how the series progresses, even DJ has dropped on in on the article!

So much trauma, 64kb segments, wrapping around, a20 gates, and overlaid virtual machines. And that’s not even really going into extenders. Looking forward to segmentation vs paging, interrupt reflection, and bi-modal handlers! Don’t cross the ISA 16Mbit DMA boundary!

so I was excited to try this protoweb thing!

mjd -protoweb

I saw this video and I was like sold! I have this PowerMac 6400/180 so I figured this would be good. The problem was my network card was acting up so I figured instead of troubleshooting it I’ll just format it and go from there.

the machine is very much an Old World Macintosh, so that limits me from OS X. It’s 603ev CPU it’s not all that advanced either. I have an 8.1 ISO that I’ve been using under 68k emulation but the limit it has is old multimedia stuff ins t 68k compatible as nobody would imagine emulation putting 68k at speeds above a gigahertz.

I went looking for a 8.6 ISO, and that is where the fun hit me again that many so-called ISO images aren’t. Rather they are giant floppy disk images with the media headers and/or partition tables being obliterated. As an ISO they don’t detect at all, and as a giant floppy, of course they don’t boot as MacOS checks if it is on read-only media.

This ISO isn’t an ISO

very annoying

I did manage to finally find one that does work however!

working ISO

I forgot where I found it though. I did save it to archive.org, since I have another 5 versions of this downloaded, none of which will boot. https://archive.org/details/mac-os-8.6-working-iso

I should also add the MacOS 8.1 CD-ROM image Ive been using as again,l I have the same issue where so many are headderless ‘floppies’ and not actual CD-ROM’s that don’t work in Cockatrice III or an actual Mac using BlueSCSI.

MacOS 8.1 CD-ROM on Cockatrice III

Sorry the image shows in black & white, but as you can see from the CD-ROM background it is in fact booted from the CD-ROM. You can download it from here: https://archive.org/details/mac-os-8.1-iso_202401

In no time, I was able to get online only to find that the power Mac plugin’s seem to be unavailable for anything and unsupported.

old netscape website

but the rendition of the old Netscape page was a treat!

Now I do have a Windows Surface RT tablet, and sure enough pluggin the proxy values, and YES the video site does work!

Warpstream on Windows RT

Very cool! So it turns out Protoweb can actually save all those old devices that work fine enough, but not fine enough for ‘Modern platforms’.

Because I hate losing my mind with Apache

I needed to setup another WordPress for something else, and I host it on a server with no https. However of course it’s fronted by a proxy with https. And WordPress embeddeds the http into the stream, and changing that with redirects causes it to ping pong like crazy.

So this is by no means the best fix, it is *A* fix. For me. YMMV.

I had to add this into the site config from apache

<Directory /var/www/mynewsite.org/>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
    Order allow,deny
    allow from all
    Require all granted
</Directory>

And does that work? no it sets up mod_rewrite (you did a2enamod it right?! RIGHT?!)

RewriteEngine on
Header always set Content-Security-Policy: upgrade-insecure-requests
RewriteRule ^$ /wordpress [L]

So the big thing here is updating the header. I had to search a bit to find that part, so yeah that was needed. The other part is that wordpress really wants to be in /wordpress not in the root, so a simple RewriteRule will put that in it’s place.

Good Grief.

I should explain my hosting situation more. I’ve been forced into some kind of nomadic situation, and thanks to some weird issue on Azure’s WordPress container thing my site ate itself. Like it literally destroyed the files. I had backups of course, and well either being evicted from a data centre because of the Windows CE Nethack scandal, or having hosting companies either go under with no warning, or drop me for being far too much traffic than they signed up for, I’d taken to not only owning my data but hosting it all myself.

I do enjoy the ‘nomad’ aspect of it all, but it’s a little crazy. I like to think of this as portable stealth hosting as I can blend into user traffic, and I can physically take my data with me. Of course, I have backups as well!

So to describe the setup I guess i need a fine MS Paint style drawing!

How the magic works

I have been using this kind of setup to some degree going back to when I setup the utzoo search engine back in 2017. I’d only expanded on it to host everything now. Working backwards I need to blend into residential traffic, so I need a typical 90’s like office vpn, which means PPTP. So going on lowendbox, I get some cheap VPS, install haproxy and PPTP server onto that. This way I’m basically renting out a static IP address for less than a Starbucks, but it let’s me have the freedom to move around and just look like user traffic, as the PPTP connection is bi-directional.

On the VPS I use a haproxy much like this:

	bind *:443 ssl crt /etc/haproxy/haproxy.pem
	redirect scheme https code 301 if !{ ssl_fc }
	mode http
	acl cloudflare src 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22
	tcp-request content accept if cloudflare
	tcp-request content reject
	acl host_utzoo hdr(host) -i utzoo.superglobalmegacorp.com
	acl host_utzoo hdr(host) -i altavista.superglobalmegacorp.com
	acl super_virt hdr(host) -i virtuallyfun.superglobalmegacorp.com
	acl host_blog hdr(host) -i virtuallyfun.com
	acl host_blog hdr(host) -i unix.superglobalmegacorp.com
	acl host_bow  hdr(host) -i bow.superglobalmegacorp.com
	acl host_blog hdr(host) -i oldlinux.superglobalmegacorp.com
	acl host_blog hdr(host) -i macmint.superglobalmegacorp.com
	acl host_blog hdr(host) -i tuhs.superglobalmegacorp.com
	acl host_nt31 hdr(host) -i winnt31.superglobalmegacorp.com
	acl host_blog hdr(host) -i superglobalmegacorp.com

        acl blog_path path_beg -i /wordpress
        acl blog hdr(host) -i virtuallyfun.com

	redirect prefix https://virtuallyfun.com code 301 if { hdr(host) -i virtuallyfun.superglobalmegacorp.com }

        http-request set-uri %[path,regsub(/wordpress/,/)] if blog_path blog
        redirect code 301 location https://virtuallyfun.com/ if blog_path blog

	use_backend utzoo if host_utzoo
	use_backend lenovo if host_blog
	use_backend nt31 if host_nt31
	use_backend bow if host_bow


backend utzoo
	server zoo1 192.168.23.10:8080

backend lenovo
	server blog1 192.168.23.10:80

backend bow
	server bow1 192.168.23.10:8888

backend nt31
	server apache 192.168.23.5:80

This way I can use various backend servers to split up various domains on the same port. Since cloudflare fronts I don’t need any weird SSL certificate with combination domains. I also get to sneak in a redirect for the old virtuallyfun.superglobalmegacorp.com, as google had a major fit about me not having it at the top level domain. The Windows NT 3.1 server is a Qemu virtual machine running on the VPS. It just has a static page so there wasn’t much point being all that sophisticated.

I then setup a Cloudflare account, and then point my domain directly to the VPS. This also let’s me grab a certificate from Cloudflare to load onto the VPS to encrypt the conversation from them to my VPS, just as the PPTP connection is also encrypted. Another advantage of PPTP over say IPsec is that older OSs like Windows NT 4.0 support it. Not to mention with tunnels being left up so incredibly long, once again I want to blend in as user traffic, and IPsec or OpenVPN just draws too much attention. It sure did in China, and sadly that’s the model I fully expect more and more of the world to be following.

Cloudflare Full Encryption

The other advantage of Cloudflare is that they do some aggressive caching which makes hosting on a residential connection viable. In this case over the last 30 days I’ve only had to ‘upload’ 41 of the 158GB of traffic.

73% of my bandwidth is cached!

If something gets popular this can make all the difference! Again, it’s key to being stealthy.

In the same way it also allows me to host my own Exchange, or any other weird application. Which then takes me to the Apache config. I have Windows 10 on the Lenovo, and loaded up WSLv1 so I could have Windows natively integrate with the filesystem. I also like that it’s got such low overhead as WSLv1 is just a subsystem, unlike v2 being a lightweight VM, like shades of Win/OS2 back in the day. My setup takes a big page from running SWGEMU on WSLv1, where I use the Win64 version of MariaDB, and the Apache/PHP is in a Linux Ubuntu distro. The other advantage here is that as my Lenovo PPTP’s into the VPS, the Apache will by default listen on port 80. Which then leads to the whole needing to set security on the headers to allow the http to become a seamless https.

I also can have multiple things listening on different ports, just as I use haproxy again locally to split out the utzoo site onto the old Apache server with all the re-write rules, and then finally to the Windows NT 4.0 workstation with the Altavista Personal desktop search.

Windows 10 performance with the blog

The overall performance on this low end Xeon E3-1225 v2 is quite acceptable.

WSLv1 processes are directly exposed.

As I had mentioned WSLv1 being a subsystem means that the processes are transparent so task-manager can immediately show yo what is going on. The opaqueness of Virtual Machines just adds to the time to identify any issues.

And all it takes is a scheduled task to dump the MariaDB, and run an xcopy onto my OneDrive, and now I’ve got a cloud backup. No plugins needed, no scripts that will break as cloud API’s are forever being depreciated and changing. Very nice!

I do like the flexibility of this being a somewhat simple setup. Not to mention being able to have more than one WSL container for various applications, being able to go so far as to break my Apache setup into multiple instances, all being ‘l7 routed’ through an instance of haproxy either at home, or in the VPS is very nice.

Oh, sure I could mess with self signed certs, and trust myself but I just didn’t want to deal with the overhead of double encryption. Maybe it’s something I’ll revisit later.

Also sorry for the ads. 2024 is starting out…. interesting.

Using an AIM-VPN EPII Plus in a Cisco 3845 or how to convert an EPII to HPII

this is a guest post by night3719

I got a 3845 for cheap with an AIM-VPN/EPII-PLUS salvaged from a 2851. At the seller’s place I installed the card and tested the 3845 there. When IOS was booting up I noticed a message along the lines of “AIM type unsupported by this platform”. I didn’t think much of it and just thought maybe I was using a version of IOS that didn’t support the module.

When I got home I threw a bunch of different IOS versions at it and nothing worked. Something was off.
As it turns out, there are 3 variants of that card, one for 1800 (BPII), one for 2800 (EPII) and one for 3800 (HPII) (note: the cards support other routers too but compatibility is a mess).

When I looked up the other variants, I immediately noticed something interesting: the modules seem identical. After looking at questions people who had similar issues posted on the Cisco community forums, something caught my eye: the output from show diag. I noticed that command spits out an EEPROM dump. As it turns out, the only difference between the cards is the contents of that EEPROM.

my card
card I found online

There are two 93C46A EEPROMs on the board, one connected to the crypto chip which probably holds config data for it and the other connected to the connector that goes to the main board. Okay, all I have to do is flash that chip with the dump I found online, right?

circled red is the EEPROM for the card, circled blue is the crypto EEPROM

Wrong.

dump from my card

The contents are obfuscated. Luckily however, two friends far smarter than I am (special thanks to Rachel Mant <[email protected]> and nyanpasu64!) figured out the obfuscation technique and one of them wrote code that encodes/decodes it

def bitSwap(value: int) -> int:
    result = 0
    for bit in range(8):
        result |= ((value >> (7 - bit)) & 1) << bit
    return result

def addrSwap(value: int) -> int:
    result = value & 1
    for bit in range(1, 6+1):
        result |= ((value >> (7 - bit)) & 1) << bit
    return result

data = [
    #data to be encoded or decoded goes here
]

for i in range(0x80):
    byte = data[addrSwap(i)]
    print(f'{bitSwap(byte):02x}', end = '\n' if (i % 16) == 15 else ' ')

I used their code to encode the output from the show diag then flashed it with my TL866. To my surprise, it worked, and the card works even on the latest IOS for this thing (15.1(4)M12a as far as I know)!

it works!

And just like that, it works!

So it turns out GCC could have been available on Windows NT the entire time!

This is going to be a bit convoluted but here goes.. GCC isn’t a monolithic compiler, instead it’s various parts are separate programs. This lets us tackle it one part at a time. And/Or bypass a lot of it until I want to tackle it.

Flow of GCC

I’m sure many people have explained this far better than I ever could but in C you write source files (obviously), the pre-processor reads those and ‘header’ files that describe interfaces to libraries, other objects, various macros and definitions (magical numbers) and the pre-processor will read those files, and do simple macro expansion and test insert/replacements to generate a single .i file at the end of it’s run.

The C compiler (cc1) now reads that single .i file and translates it into native assembly. This allows for ‘mid/high level’ aspects of C to be machine independent (portable) but now will be written into a very system dependant assembly file, the single .S file. One thing of note is that so far everything is text files. You can edit the assembly file as you would any document, or even further ‘process’ it if needed/wanted.

The assembler ax386 (GAS) will then read the single assembly file and write a a binary object file hi.OBJ. There typically isn’t all that much to be said about assemblers although fancier ones allow for really strong Macro capabilities like Microsoft MASM.

From here on, it’s all binary objects!

The linker then takes your object files, and links them together with other system objects and system libraries into an executable, in this case. Linkers can build all kinds of other things, but for now we’re just pretending its static C compilation like it’s the 1970’s.

At it’s heart GCC processes text files.

The first part in this insane experiment, is to build GCC 1.40 with Microsoft Visual C++ 1.0. Surprisingly it didn’t take an insane amount of messing with stuff, and I got an executable! But everything it compiled failed to assemble. Looking at this fragment, even if you don’t know i386 assembly you might spot the error:

main:
        pushl %ebp
        a b,c
        pushl %esi
        pushl %ebx

Yeah, it’s the “a b,c” part. Those are NOT valid i386 opcodes!

Just because it compiled didn’t mean it actually worked.

I used MinGW to build the same source, same Makefile, and I got a working executable. Annoyed I started compiling random files with Microsoft C, and finally found the file that broke it all, it turned out to be insn-output.c needing to be compiled with the “/D__STDC__” flags. A quick modification of the Makefile and now I have a working CC1!

Okay, great, it’s well known back in the early dangerous ages of the 1980’s/1990’s that everyone wasn’t running Linux, nor were binary distributions of GCC that far spread, rather I think to re-enforce the source was available it was expected that you’d use your system compiler. Systems like DJGPP/EMX take the path of binding a.out object files into something that MS-DOS can run via a dos extender, or the bind utility to allow you to run the a.out on OS/2. What I wan’t to do is verify that in fact Windows NT was a viable host for GCC back in the public pre-releases of 1991.

I’m sticking with the December build 239 version as it has working floating point. Something that GCC has intrinsic support of, and I don’t feel like trying to work out emulation.

The next step is to try to build it with the family mode-OS/2 version of the C compiler, which of course lead to the real issue of this 16bit hosted cross compiler:

        cl386 /u /Od /Ic:\MSVC32S\C386\INCLUDE /I. /Iconfig /c combine.c
Microsoft (R) Microsoft 386 C Compiler. Version 1.00.075
Copyright (c) Microsoft Corp 1984-1989. All rights reserved.

combine.c
combine.c(1734) : fatal error C1002: compiler is out of heap space in Pass 2
NMAKE : fatal error U1077: 'C:\WINDOWS\system32\cmd.exe' : return code '0x2'
Stop.

Very frustrating. I tried mixing and matching from Visual C++ 1.0 & this old compiler, and while it did compile, it doesn’t run. does it mean anything?!

GCC 1.40 compiled by Microsoft 386 C Compiler. Version 1.00.075

I should point out that this should be an expected working configuration as GCC does build on Xenix using the 32bit Microsoft C 5.1/386 compiler. Furthered again that Xenix and these 1991 versions of NT use the same 32bit OMF object format. And expanding on the Xenixnt experiment using the Xenix’ified GAS assembler with old Visual C++ includes & libraries to produce a possible retro-early port of GCC to NT, the next move is to bulid GAS on NT.

Xenix GAS 1.38 compiled by by Microsoft 386 C Compiler. Version 1.00.075

GAS gave me some weird issues with ctype.h where it runs fine with the one from Visual C++ 1.0 but the OS/2 & NT pre-release both fail. However the old Pre-release compiler cannot deal with the much newer ctype include file. So after much hammering I amputated whatever was bothering it, and it’s just enough to build & run. Great!

Going back to the phases, I used a simple hello world program:

void main() {
 printf("Hello World!\n");
}

While not being a good program, it doesn’t include stdio.h, nor does it return anything. It’s terrible. But in this case it allows me to be lazy and sidestep the pre-processor cpp.exe. This way I can just directly run it through cc1 and get my assembler file hi.S

Next I pass it to ax386 (GAS) and get the resulting object file hi.OBJ

And finally link it with link.exe in this case.

Hello World from GCC 1.40 on NT!

And with all the drama I’ve now compiled a simple hello world program on Windows NT.

If it were 1991, I would hollow out gcc.c so it doesn’t use signals or forks to invoke the needed phases, and of course build the pre-processor. In addition, libgcc needs to be compiled to allow for floating point operations to work correctly. None of which is impossible, although I’m not sure it’s all that needed as it isn’t 1991.

phoon

With a little bit more work, I got the floating point support to compile, which relies on both a working ‘native’ compiler, and a working GCC to compile the 2nd half. I usually use phoon, or Phases of the Moon, to test floating point, and as you can see, it’s working!

I’m not sure if there was a 32bit version of Microsoft C/386 available for Microsoft OS/2 2.00 betas. Also, I don’t know if the Microsoft link386 for OS/2 can also link Xenix 386 object files? Would it have been possible to bootstrap GCC/GAS on Microsoft OS/2 2.00? I really don’t know, and as of this writing no versions of the old Microsoft OS/2 2.00 betas have surfaced.

** update from the future, turns out that I found a way to convince the cl386 compilers from the NT Pre-Releases in 1991 to re-build an existing GCC that was built for NT. The catch is the linker, LINK386 of course, as the format was constantly changing. However the object files are fine, and I was able to just copy them over on diskette and re-link the compiler. It even ran. It’s not tested at all, so it turns out the 1989 compiler wasn’t good enough, but the 1991 was.

GCC 1.40 on OS/2 2.00 beta 6.123

It’s interesting to me to see that even before GCC 2.6, that vintage versions from 1991 would compile and run directly on Windows NT.

I uploaded the source on github, along with some binaries.

The Rise of Unix. The Seeds of its Fall. / A Chronicle of the Unix Wars

It’s not mine, rather it’s Asianometry‘s. It’s a nice overview of the rise of Unix. I’d recommend checking it out, it’s pretty good. And of course, as I’m referenced!

The Rise of Unix. The Seeds of its Fall.

And part 2: A Chronicle of the Unix Wars

A Chronicle of the Unix Wars (youtube.com)

Years ago I had tried to make these old OS’s accessible to the masses with a simple windows installer where you could click & run these ancient artifacts. Say 4.2BSD.

Download BSD4.2-install-0.3.exe (Ancient UNIX/BSD emulation on Windows) (sourceforge.net)

Installing should be pretty straight forward, I just put the license as a click through and accept defaults.

Starting BSD via ‘RUN BSD42’ 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 ‘Attach a PTY’ which will spawn another Tera Term, prompting you to login.

telnettting into the VAX

You can login as root, there is no password, and now you are up and running your virtual VAX with 4.2BSD!

All the items

I converted many of the old documents into PDF’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’m not sure if I succeded.

776 downloads

As it sits now, since 2007 it’s had 776 downloads. I’d never really gotten any feedback so I’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’d been unsure if any of them went anywhere. It’s why I found these videos so interesting as at least the image artifacts got used for something!

But in the off hand, maybe this can encourage some Unix curious into a larger world.

Other downloads in the same scope are:

Enjoy!

Win32Emu / DIY WOW

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

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.

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  was pretty simple – just map the appropriate sections to the appropriate areas, fix up import tables, and start executing.

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  which is trapped by the emulator and thunked up to execute the API call on the host.

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.

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.

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.

It’s amazing, it’s reversi!

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.

Freecell
Minesweeper

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.

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.

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.

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

There’s still some DLL relocation/rebasing issues, but Reversi is finally working in this homebrewed WOW!

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

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.

I also want to get more “useful” applications running, like development tools (i.e. the MSVC command line utilities – CL, MAKE, LINK, etc.) and CMD. Most of that probably involves implementing more thunks and potentially fixing CPU bugs.

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.

For those who want to play along at home, you can download the binary snapshot here: w32emu.zip

A more complete version of the writeup is available here: https://bhty.github.io/og/win32emu_VirtuallyFun_Post.htm and you can find the project here https://github.com/BHTY/Win32Emu/.