Friday, July 21, 2023

Apple's Interactive Television Box: hacking the Set Top Box System 7.1 in ROM

This article has been revised with recollections and corrections from former Apple employee Al Kossow, some good folks on Hacker News and the Vintage Computer Festival forums, and an anonymous individual with high-level knowledge of the project.
One of the coolest things to come along in the 68K Mac homebrew community is the ROM Boot Disk concept. Classic Macs have an unusually large ROM that contains a fair bit of the Mac OS, which was true even in the G3 New World Mac era (it was just on disk), so it's somewhat surprising that only one Mac officially could boot the Mac OS entirely from ROM, namely the Macintosh Classic (hold down Cmd-Option-X-O to boot from a hidden HFS volume with System 6.0.3). For many Macs that can take a ROM SIMM, you can embed a ROM volume in the Mac ROM that can even be mirrored to a RAM disk. You can even buy them pre-populated. How's that for immutability?

Well, it turns out Apple themselves were the first ones to implement a flashable Mac OS ROM volume in 1994, but hardly anyone noticed — because it was only ever used publicly in a minority subset of one of the most unusual of the Macintosh-derived systems, the Apple Interactive Television Box (a/k/a AITB or the Apple Set Top Box/STB). And that's what we're going to dig into — and reprogram! — today.

The AITB/STB was Apple's attempt to get into the early set-top box market of the 1990s. The dominance of the Apple TV today is a late phenomenon; Apple was in no position to launch such a product on their own in that era, though with the recent introduction of their QuickTime multimedia framework in 1991, they were a strong candidate for a technology partner.

Apple was approached in the middle of an Oracle and British Telecom initiative to produce cable-based set top boxes for premium TV content after the partnership's initial hardware developer failed to deliver. Apple forged an alliance with Oracle and parallel computing vendor nCube (Larry Ellison then being its single biggest stockholder) to develop the headend-to-customer infrastructure, with Apple developing the front end client box and nCube boxes running Oracle Media Server handling the back end. All of this was to occur using MPEG-1 video with QuickTime as the playback system, specifically selected because of MPEG-1's bitrate of 1.5Mbit/sec and enough to run over a T1/E1 line. Plus, hardware decoders for the format already existed, meaning the device wouldn't have to rely on the CPU for smooth playback.

Because of time constraints the STBs were developed both in Cupertino and Austin in late 1993 and early 1994; the software came from Cupertino, but hardware development occurred in both places, and final production took place in Austin. Some work on the hardware was done by Ben Yung's Video Architecture Group in Cupertino in Valley Green 6, and the machine incorporated software from the QuickTime team in DeAnza 3. To get to market faster, it was decided to base it on stripped-down 1993 Quadra 605 hardware with extra silicon for the media features, but kept serial, ADB and SCSI connections to allow it to run compatible CD-ROMs (sort of a Pippin before the Pippin) with plans to sell it for $750 [2023 dollars about $1500]. You could even hook up a printer to the serial port, but no storage was onboard: this device was to strictly boot from a central network link — in this case a T1/E1 — or from CD. While Apple delivered the first prototypes to British Telecom in the spring of 1994, the unit first emerged publicly at Macworld Tokyo in February 1995 where it was demonstrated to attendees and later at the National Association of Broadcasters Show in Las Vegas in April 1995. There were at least two major hardware versions, STB1 and STB3 (no STB2s are known), with the STB3 being the most "common."

Apple partnered with cable TV companies for content delivery and AITBs were part of at least several trial deployments across the United States and Europe as well as British Telecom's; Disney even used it briefly in Epcot. However, there were concerns about providing enough licensed and on-demand content, and while customers might buy that content, they tended to compensate by cutting subscriptions to the premium channels that the cable companies relied on as a regular income stream. The situation wasn't much better as a retail product given that home broadband was in its infancy and the product market was already too small for a boutique system. On top of that, the $300,000 [in 2023 over $600,000!] official development system (consisting of an nCube MediaCUBE server, 8 AITBs and 10GB of storage) made the already rarefied product thoroughly unattractive to developers, and with DOCSIS on the horizon wiring up T1 lines everywhere just didn't seem to pay off. Apple never ended up launching the hardware for retail sale, the existing trials were terminated, and most of the boxes were ultimately recalled and destroyed.

But, like all failed experiments, not all of them disappeared and various units have made their way into the hands of collectors and hackers. Over the years I've acquired two STB3 systems myself, one a non-working "production" model and the other a mostly functional DVT prototype. This prototype is not FCC-approved but is fundamentally identical to the "production" M4120 unit, so we'll be discussing mostly the prototype here since it works and is in much better shape. Here it is:

The STB3 shipped in a fairly dramatic black case with a top lid. It was designed to fit into any typical home entertainment centre and will support the weight of a typical CRT television.
The only front control was a power button. Depending on the installed ROM, the power LED might show any or no colour at all. We'll talk about that a little later. Under the Apple logo was an IR sensor for which I lack the official remote control. (That's okay because it turns out we don't actually need it to hack it.)
The rear ports. Standard, the STB3 came with connectors for power (using a regular LC power supply), SCSI (using the Apple HDI-30 connector), SCART TV and VCR (both blocked), RF in/out from an antenna or cable TV connection, 8P8C network (but not Ethernet: this is for a T1/E1), standard Mac Mini-DIN serial, Mac S-video out, composite video, and stereo phono audio. A rubber grommet covers the Kensington lock slot, which I imagine was used in the hotel deployments. On the side, not visible here, is a single ADB port which only officially supports a mouse.

The BT version of these systems (labeled with BT branding as a "Interactive TV System Voyager 2000") reportedly used an ADSL connection, though I've never seen such a unit personally.

But what this unit also has, and most STBs don't, is a developer video card with a Mac DA-15 connector. Sadly, I've never been able to get it to work. More below when we open the case.
On the underside is this disclaimer that the unit is not FCC-approved. This unit is clearly further along than an EVT prototype like our "Shiner ESB" Apple Network Server prototype, but because it's not FCC approved it's probably not a PVT, so therefore I'm concluding it's a DVT like our Macintosh Portable prototype.
Removing the top lid (there's a screw you may need to remove from the back), we see the video card, the mainboard and the power supply, which is a regular Q605 supply except with a black frame around the power port (the Q605/LC475 supply is in Apple Platinum beige). Although there is a spot where a cooling fan could go, there is neither mounting nor a power connector for one in both my units. The little three solder points next to it are where one can be installed, and some units exist where a fan is present.
The CPU, like the Quadra 605, is a 25MHz 68LC040. Other chips visible here are an Apple 343S0138-A (fabbed by TI) handling the PDS slot, an Apple 34320164-b (VLSI) MEMCjr memory controller, a TI TMXE320AV110 that appears to be an audio DSP, an NCR 53C96 SCSI controller, a Zilog Z8530 SCC for the serial port, and a Philips SAA7188A digital YUV to NTSC/PAL encoder (earlier Philips chips appear in the AV Macs). The RAM and ROM SIMMs are next to that, along with 4MB of RAM soldered to the board.
In front, red lines go to the power switch and LED, blue lines to the IR sensor, and white lines to the side-mounted ADB port.
And inside the front, just next to the red lines, is the board copyright (1995) and number (820-0638-01, which would be a prototype board designation).
The board has a single PDS slot, occupied in the prototype by a video card which connects with a 90-degree adapter. This card is a simple 2D framebuffer with four 256Kx8 VRAMs to equal 1MB on board. Very few of these cards existed and seem to have only been part of developer machines.
The card identifies itself as a Micro Conversions X62SC01 (Revision A), which resembles the Micro Conversions 1724PD graphics card for the LC III and Performa 630. If there existed a driver specifically for this card, it must have been on whatever developer-bootable disk this unit didn't come with.
Pulling the card out of my working STB was a no-go; it's pretty much there for keeps (not interested in trying to pry it out lest I damage the card, the board, or both). Instead, we'll fill in the gap by switching here to the non-working "production" model, which unfortunately was improperly stored and suffered from oxidation damage. The chip with the white sticker is a socketed DIP ROM labeled "A3N(LS) C/SUM 519D8 95@@" which appears in other NTSC STB3s. The MPEG decoder is conveniently marked, a C-Cube Microsystems CL450-P160, the same one Apple used earlier with their MPEG Media System card. Next to that is an Xilinx FPGA that likely serves as support video hardware.

The other marked chip, with green oxidation damage around the pins, is a Brooktree Bt8069 T1 transceiver. Other than the Zilog SCC the Bt8069 is the only networking chip obviously on the board; in particular, no Ethernet chips are visible. If the British Telecom units were truly ADSL, it would have had to have a different chip here or some sort of external transceiver box: even in situations where the T1 line is provisioned over DSL, that's usually HDSL, and the technologies are otherwise not interchangeable.

This unit is labeled as production and has an FCC ID and clearance sticker identifying it as a model M4120 (but with no formal name). This unit came from my hometown of San Diego County, California, based on the asset tag from The Lightspan Partnership, Inc. Lightspan Partnership, later just Lightspan, was founded in 1993 to develop edutainment software and produced a line of school-oriented Sony PlayStation titles which were sold to districts for classroom use. However, the original concept was to distribute the software via cable television so that students and parents could use it at home. This unit was obviously part of that initial, unrealized initiative. In 2003 Lightspan merged with PLATO Learning, Inc. (now Edmentum), one of the inheritors of the Control Data PLATO legacy, and subsequently ceased to exist.
But despite being labeled as a production, FCC-certified unit, it still has the same prototype motherboard code as the DVT unit.
Let's go back to the RAM and ROM for a second. There is a RAM slot here and you can put extra RAM into it, same as you would with a regular Q605, but the ROM's the more interesting part.

No, I'm not talking about these green mask ROMs that most owners of an STB3 have:

If you dump one (I have two which are the same), you'll get a ROM checksum ($ff7439ee, SHA-1 1d833125adf553a50f5994746c2c01aa5a1dbbf2) exactly identical to the Quadra 605, which isn't surprising because the STB is derived from it. With a Q605 ROM installed, these units won't display a picture but they will let you boot over SCSI. Add something like Farallon/Netopia Timbuktu and a LocalTalk connection and you can remotely use one over the network from another classic Mac. Not too useful, but hey, they're stylish and rare, and it's great fun at parties (I'm told, I'm never invited to those sorts of parties).

Unfortunately, my unit, though it would initially boot from a BlueSCSI, one day suddenly decided it wouldn't. I've never been able to get it to boot from any SCSI device since, no matter what keys are held down, Option, Cmd-Option-Shift-Delete, dead chicken burnt offering, nothing. The unit otherwise works normally which leads me to suspect a fuse somewhere and/or the SCSI controller. (Don't kneejerk and say bad caps. I will hurt you.)

That brings us to this ROM.

This red ROM stick, labeled AP1654-01, has four 256K flash chips front and back to equal 2MB. Notice the silkscreened name "RLC FLASH SIMM." These appear to have been made initially for the RISC LC, the famous and heavily modified LC-based development prototype that emulated a 68K Mac with full compatibility and became the direct ancestor of the Power Macintosh.

There are many versions of this ROM, and this one is not labeled like most of the others in that linked image. However, I have no reason to suspect this particular one behaves much differently from the others.

The red ROM's biggest difference from the green ROM in that the TV outputs are enabled. When you switch on (with the back power switch) an STB3 with the red ROM, after a pause of a few seconds the LED over the power button lights red, and then shortly after yellow. In the Setup Guide, this indicates POST, followed by standby. This is very different from units with a Q605 ROM in which the LED never lights and the machine instead starts from the ADB power key, like any other Mac of this era would normally.

Pressing the power button when the LED is yellow turns the LED green and this image appears on a connected composite or S-video display, captured on my INOGENI box:

But, invariably, 30 seconds-ish later, you get this:
indicating an expected response from the server never arrived. I don't know what the green button on the remote does (the manual simply says to "see the interactive service provider's instructions" for the four colour buttons). I connected speakers to the audio out but the unit makes no sound.

I don't know which human-readable version of the ROM this is, but we can dump it:

The best tool for this purpose is of course Doug Brown's flash SIMM programmer, which can both read these ROM SIMMs (used in many 68K Macs) and write to replacement flash ROM sticks. The 2MB dump we get has a checksum of $b7025504 (the first four bytes as a 32-bit big-endian unsigned integer), a version word of $077d (i.e., 1917, bytes eight and nine as a 16-bit big-endian unsigned short), and a SHA-1 of 911eaafc5ccfe6823a7be61d44aaf0a63d081118. What we're going to do with this dump is based on this particular ROM version. The rest of this article may or may not fully apply to other versions and of course you follow along with your real device at your own risk.

The first step with any dump is see what binwalk makes of it, and other than copyright messages, it finds a couple surprising things are present. Nine, to be exact.

% binwalk RED.rom

941976        0xE5F98         Copyright string: "Copyright C-Cube Microsystems 1992"
1090813       0x10A4FD        Copyright string: "Copyright 1990-91 Apple Computer Inc. Copyright 1981 Linotype AG Copyright 1990-91 Type Solutions Inc.1.0"
1090851       0x10A523        Copyright string: "Copyright 1981 Linotype AG Copyright 1990-91 Type Solutions Inc.1.0"
1090878       0x10A53E        Copyright string: "Copyright 1990-91 Type Solutions Inc.1.0"
1844352       0x1C2480        JPEG image data, JFIF standard 1.01
1846358       0x1C2C56        JPEG image data, JFIF standard 1.01
1848250       0x1C33BA        JPEG image data, JFIF standard 1.01
1849933       0x1C3A4D        JPEG image data, JFIF standard 1.01
1851587       0x1C40C3        JPEG image data, JFIF standard 1.01
1853288       0x1C4768        JPEG image data, JFIF standard 1.01
1855867       0x1C517B        JPEG image data, JFIF standard 1.01
1857571       0x1C5823        JPEG image data, JFIF standard 1.01
1859146       0x1C5E4A        JPEG image data, JFIF standard 1.01
1871674       0x1C8F3A        Copyright string: "Copyright 1987-1991"

The copyrights reference fonts, but also C-Cube, the manufacturer of the MPEG decoder. It also finds nine JPEG images:

These are pictures primarily of the QuickTime development team and were actually embedded in QuickTime. The top row is Sean Allen, Jim Batson and Mike Dodd. The second row is Fred Huxham — remember that name — Peter Hoddie and Jim Nitchals. On the bottom is Kip Olson, David Van Brink and an individual yet to be identified. Most of the work was done by Fred Huxham and Fred Monroe, who is not pictured, though Olson wrote most of the demo apps used for Macworld Tokyo and other demonstrations, Batson helped create the scaled-down QuickTime components the device uses, Jay Michael Puckett (not pictured) appears as a developer in some logs, and Giovanni Agnoli (also not pictured) joined the STB team to assist in summer 1994.

More relevantly, though, now that we have a ROM dump we've just got to hack it. Since it's displaying a message, let's see if we can modify the message as a small proof of concept. strings, that always useful tool, shows that the "Sorry!" message appears in two places. Modifying the first one is sufficient:

This will change the checksum of the ROM, which is computed as the sum of all the 16-bit big endian shorts from byte 4 onward and truncated to 32 bits. The tools I wrote up to handle all this are in this Github project. Use to recompute the ROM checksum and then use the hex editor to edit the first four bytes to match.
Then get yourself a couple 2MB flash ROMs SIMMs. They must be exactly 2MB in size; larger ROMs won't work even if you "echo" the bytes. I used the 2MB ROM-inator II from Big Mess O'Wires but CayMac's 2MB ROM should also do the job; CayMac also sells new SIMM programmers (I am not affiliated with BMOW or CayMac).

Burn the ROM in your programmer using the SIMM programmer tool, make sure your STB3 is off, and install it in the ROM SIMM slot near the RAM slot. On the programmer, the SIMM skull and crossbones should face the skull and crossbones on the circuitboard; on the STB, the SIMM skull and crossbones should face the RAM. Connect up some sort of composite monitor and switch it on.

Our plea for help duly appears. This simple demonstration proves that the only thing we need to do to modify the ROM is update the checksum; nothing else on the board appears to check it. It's now time to figure out what's there and how it's organized.

Many Apple ROMs are segmented into discrete resources, which are functionally equivalent with on-disk HFS resources attached to files, and can be accessed from the Toolbox in the same fashion. For example, here's the header of the (unused, disabled and not implemented) .netBOOT driver resource in the green Quadra 605 ROM:

00051c80  18 00 00 00 00 00 00 00  00 0e dc 70 00 05 1c b0  |...........p....|
00051c90  44 52 56 52 00 31 58 08  2e 6e 65 74 42 4f 4f 54  |DRVR.1X..netBOOT|
00051ca0  00 00 00 00 c0 a0 00 00  00 00 08 80 00 00 03 04  |................|

We can scan the red ROM dump for similar resource headers. Starting at offset $0000, the first big-endian 32-bit word is always the ROM checksum and the second is the starting address for the boot code (technically the first sets the stack pointer, but the ROM glosses over this). We page through opaque binary data awhile until we start seeing structured patterns every so often. The first one of these patterns we get to is this.

000ac210  78 00 00 00 00 00 00 00  00 00 00 00 00 0a b3 70  |x..............p|
000ac220  62 6f 6f 74 00 03 58 04  4d 61 69 6e 6b 63 6b 63  |boot..X.Mainkckc|
000ac230  4b 75 72 74 c0 a0 00 00  00 00 07 6a 00 00 00 64  |Kurt.......j...d|

This is our first ROM resource, boot#3, named MainkckcKurt (much like the string Gary, presumably Gary Davidian, shows up a lot in Mac ROMs, the name Kurt is all over this one — from the "kc" bit I'm guessing Kurt Clark, who was an Apple senior firmware and system software engineer at the time of the AITB's development and also appears frequently in ROMs of the era). The hex byte 78 indicates an enabled, live resource.

The ROM resources in the red ROM are stored somewhat back to front with the "header" actually serving as a footer; the resource runs from the fourth word (here $000ab370) to the beginning of the footer. How do we know it's laid out like that? Because of what we find a little later on:

000ac980  70 73 6c 74 00 14 70 73  6c 74 00 1a 73 6e 64 20  |pslt..pslt..snd |
000ac990  00 01 77 65 64 67 e9 81  77 65 64 67 e9 80 6b 63  |..wedg..wedg..kc|
000ac9a0  78 00 00 00 00 00 00 00  00 0a c2 10 00 0a c2 40  |x..............@|
000ac9b0  72 6f 76 6d 00 00 58 00  6b 63 6b 63 6b 63 6b 63  |rovm..X.kckckckc|
000ac9c0  4b 75 72 74 c0 a0 00 00  00 08 70 0c 00 00 00 6c  |Kurt......p....l|
000ac9d0  4c 4b 60 00 00 86 44 18  00 00 06 53 79 73 74 65  |LK`...D....Syste|
000ac9e0  6d 00 00 00 00 00 00 00  00 00 06 46 69 6e 64 65  |m..........Finde|
000ac9f0  72 00 00 00 00 00 00 00  00 00 07 4d 61 63 73 42  |r..........MacsB|
000aca00  75 67 00 00 00 00 00 00  00 00 0c 44 69 73 61 73  |ug.........Disas|
000aca10  73 65 6d 62 6c 65 72 00  00 00 0d 53 74 61 72 74  |sembler....Start|
000aca20  55 70 53 63 72 65 65 6e  00 00 06 46 69 6e 64 65  |UpScreen...Finde|
000aca30  72 00 00 00 00 00 00 00  00 00 09 43 6c 69 70 62  |r..........Clipb|
000aca40  6f 61 72 64 00 00 00 00  00 00 00 0a 00 14 00 00  |oard............|

The characters LK herald HFS boot blocks. Yes, friends, there's an embedded disk image here, and it's doubtful the resource code rovm is used to reference it.

There are many fun strings in that disk image:

000af1d0  46 72 65 64 54 56 aa 0d  0d 42 72 6f 75 67 68 74  |FredTV...Brought|
000af1e0  20 74 6f 20 79 6f 75 20  62 79 20 46 72 65 64 20  | to you by Fred |
000af1f0  48 75 78 68 61 6d 20 61  6e 64 20 46 72 65 64 20  |Huxham and Fred |
000af200  4d 6f 6e 72 6f 65 2e 0d  0d a9 20 41 70 70 6c 65  |Monroe.... Apple|
000af210  20 43 6f 6d 70 75 74 65  72 2c 20 49 6e 63 2e 20  | Computer, Inc. |
000af220  31 39 39 33 0d 41 6c 6c  20 52 69 67 68 74 73 20  |1993.All Rights |
000af230  52 65 73 65 72 76 65 64  2e 0d 81 e2 20 30 01 60  |Reserved.... 0.`|

Although it was known that the AITB ROM had portions of System 7.1, this red ROM actually seems to contain an entire, self-contained, miniature bootable image. There's no reason to have the string Welcome to Macintosh. unless a working System file were part of it:

000b2930  1a 00 6c 00 c0 57 65 6c  63 6f 6d 65 20 74 6f 20  |..l..Welcome to |
000b2940  4d 61 63 69 6e 74 6f 73  68 2e 00 b1 7a 00 18 00  |Macintosh...z...|
000b2950  7e 00 c0 44 65 62 75 67  67 65 72 20 69 6e 73 74  |~..Debugger inst|
000b2960  61 6c 6c 65 64 2e 00 b1  77 00 14 00 7e 00 c0 45  |alled...w...~..E|
000b2970  78 74 65 6e 73 69 6f 6e  73 20 6f 66 66 2e 00 b1  |xtensions off...|
000b2980  79 00 ca 00 5e 00 72 54  68 69 73 20 73 74 61 72  |y...^.rThis star|
000b2990  74 75 70 20 64 69 73 6b  20 77 69 6c 6c 20 6e 6f  |tup disk will no|
000b29a0  74 20 77 6f 72 6b 20 6f  6e 20 74 68 69 73 20 4d  |t work on this M|
000b29b0  61 63 69 6e 74 6f 73 68  2f 6d 6f 64 65 6c 2e 20  |acintosh/model. |
000b3e50  6d 21 40 2d 04 42 af 06  04 00 00 00 55 54 4d 61  |m!@-.B......UTMa|
000b3e60  63 69 6e 74 6f 73 68 20  53 79 73 74 65 6d 20 76  |cintosh System v|
000b3e70  65 72 73 69 6f 6e 20 37  2e 31 0d 0d 0d a9 20 41  |ersion 7.1.... A|
000b3e80  70 70 6c 65 20 43 6f 6d  70 75 74 65 72 2c 20 49  |pple Computer, I|
000b3e90  6e 63 2e 20 31 39 38 33  2d 31 39 39 32 0d 41 6c  |nc. 1983-1992.Al|
000b3ea0  6c 20 72 69 67 68 74 73  20 72 65 73 65 72 76 65  |l rights reserve|
000b3eb0  64 2e 00 00 01 f5 a8 9f  65 72 00 12 09 01 00 00  ||

Eventually we come to its footer, which now enables us to extract it.

001339d0  78 00 00 00 00 00 00 00  00 0a c9 a0 00 0a c9 d0  |x...............|
001339e0  64 69 73 6b 00 00 58 00  6b 63 6b 63 6b 63 6b 63  |disk..X.kckckckc|
001339f0  4b 75 72 74 c0 a0 00 00  00 00 07 50 00 00 00 74  |Kurt.......P...t|

It's a disk, resource #0. That sounds more likely as a type code. If you look at the third and fourth 32-bit words (big-endian, again, as G-d intended), you'll find it links back to the last footer at $000ac9a0 (the rovm resource), allowing us to scan the file by walking back references, and the address $000ac9d0 is where we found the boot block, so that must be the starting address for this resource. That means disk#0 occupies $000ac9d0 to the beginning of the footer at $001339d0.

If this is a bootable Mac OS System 7 image, it should act like it. And, to my delight, it does. The manual says nothing about connecting an ADB keyboard to it, only a mouse, but ADB keyboards work fine. If you hold down the SHIFT key while turning the rear power switch on and waiting for it to turn yellow, you'll lose the Apple background when you power on from the front, exactly as if an extension didn't load.

This behaviour suggests that when you first turn it on, it's doing its memory test and POST, then turns on the red LED while searching for and booting the minimal Mac OS, then turns on the yellow LED when, I guess, the "Finder" (such as it is) is ready to find its mothership.

Other typical Mac key combinations work, too. Pressing Command-Q will reset the machine when the timeout error message appears, as if quitting any other app. If you press Command-Option-Escape in an attempt to kill the task, you'll reset it also, or Command-Power, though possibly only at the point the timeout error message is present — one suspects this front-end program doesn't call WaitNextEvent very much. (In fact, it turns out it doesn't by the point, but that's a spoiler from near the end of this article.) It seems virtually anything that would cause a quit or system error (or any system dialogue box) will immediately force a restart. Incidentally, there is no startup chime or system beep, though there does appear to be a System Beep resource (snd #1).

Can the STB3 red ROM boot from anything else? The manual says it can access a CD-ROM drive connected via SCSI, and there are strings in the ROM that make reference to SCSI, but these appear to be within the byte range we identified as part of the disk image (and my SCSI isn't bootable). Apart from that, however, we now have enough understanding of how its ROM is laid out to write something that will walk it. (Eventually I'll extend it to work with other Mac ROMs, but right now the code just works with this red one.) We'll use to see what driver resources are present and if there are any other disk images.

% ../ RED.rom | grep -ai DRVR
[78000000] found DRVR #93 at 0x00133a00 0x00134150 ".STBDiskDriverkckckckckc" 
% ../ RED.rom | grep -ai disk
[78000000] found disk #0 at 0x000ac9d0 0x001339d0 "kckckckcKurt��" 
[78000000] found DRVR #93 at 0x00133a00 0x00134150 ".STBDiskDriverkckckckckc"
(various string resources elided)

There appears to be only one DRVR, versus the multiple found in the Q605 ROM (such as one for the floppy drive), plus only one ROM disk image. If it can load from SCSI at all, it appears to be handled by the OS in the ROM disk image rather than the firmware directly, suggesting a regular MacOS volume might not boot as such. Alternatively, doing so may not have been supported with this version of the ROM. Resource STR #46396 does have the interesting string "Manages file access to CDi discs for QuickTime media handlers" which suggests disc support may have been intended for greenbook CD-i.

Of other resources present, there are several thng resources, including an "STB3 Component" that "Supports the hardware dependent features of STB3." and an "I2C Component" that "Supports I2C using Cuda," and a number of cdec (QuickTime codec) resources for Cinepak, Photo/JPEG, Apple Animation ("Decompresses images compressed using run length encoding") and Apple Graphics ("Decompresses images compressed using Sean's secret recipe") and, of course, MPEG-1. These components are specific to the STB and embedded elsewhere in ROM, not as part of the bootable image.

As for the OS itself, we'll now extract that byte range we computed and treat it as a disk image. Both SheepShaver and Mini vMac will mount it, but we'll use SheepShaver first to illustrate a little of what's there.

First off, we're dealing with a disk image smaller than an 800K floppy; it's 540K in size. As a result the System Folder is very abbreviated: two mysterious INITs, NMIer and TSDrvr INIT - 8/8, and very small Finder and System files. There is one font in the Fonts folder (there are other font references in the System file), and nothing in Apple Menu Items. The TSDrvr extension may be related to the known set of Set Top Box extensions though none of those files have so far worked with any STB using the green ROM booting a conventional version of Mac OS. If indeed related, then the TS part of the name likely refers to MPEG transport streams and handles framing as movie data comes over the wire.

The other file is named MPEGStill. It has a single ckid (check ID) resource from MPW Projector, which is the Macintosh Programmer's Workshop version control system, and (among other binary data) that resource contains the strings SetTopProj (the project name, no doubt), Tidbits (probably the component or subproject, probably not the long-lived Mac newsletter), jay michael puckett (author), and AppleMPEGStill.

But the last string is the most interesting. It says it's a new still for non-BT trials. So what's the still image?

It's ... an MPEG-1 frame. And QuickTime will play it:
There's our image, as CIF PAL 352x288. Notice there's only one frame here; presumably the BT STBs used a British Telecom image for their backdrop still instead. Most likely the hardware MPEG decoder, via the built-in ROM codecs, is being used to decode and display the frame.

For our first trick, let's create a new still frame of our own. There are a few gotchas. First of all, SheepShaver seems to wipe the boot blocks when it unmounts the image, and also unblesses the System Folder, making the resulting disk image unbootable by the STB. (I'll say benignly this was the source of a lot of cussing when the red LED would turn on but then nothing else happened.) We'll use it to explore the image but for development we'll use Mini vMac instead, which also unblesses the System Folder, but if you boot the emulated Mac (I use the Macintosh II emulation) with both your boot volume and the STB volume on the command line, it leaves the boot blocks alone. We can fix the "unblessed" folder after Mini vMac unmounts it.

If we feed the data fork to file and ffmpeg, this is what we get.

% file MPEGStill
MPEGStill: MPEG sequence, v1, progressive Y'CbCr 4:2:0 video, CIF PAL, 25 fps
% ffmpeg -i MPEGStill
[mpegvideo @ 0x1001f8d4b70] Estimating duration from bitrate, this may be inaccurate
Input #0, mpegvideo, from 'MPEGStill':
  Duration: 00:00:00.00, bitrate: 104786 kb/s
  Stream #0:0: Video: mpeg1video, yuv420p(tv), 352x288 [SAR 1:1 DAR 11:9], 104857 kb/s, 25 tbr, 1200k tbn

We'll use the famous SMPTE colour bars at a 4:3 aspect ratio. Based on the specs above, we should be able to approximate it with a command line line ffmpeg -i smpte.png -s 352x288 -r 25 -c:v mpeg1video -pix_fmt yuv420p nu.mpg, but this doesn't quite work.

The reason is it doesn't is because ffmpeg generated an MPEG program stream and the decoder hardware wants an MPEG elementary stream.

% file nu.mpg
nu.mpg: MPEG sequence, v1, system multiplex

While I'm sure we can get ffmpeg to cough up the video stream alone, sometimes the simplest approach is to use an additional tool, in this case mpegdemux. It compiled out of the box on my Fedora Linux-based POWER9 Raptor Talos II workstation and generated a file that matches the original MPEGStill (and is smaller, too).

% mpegdemux -d -s 0xe0 nu.mpg nuu.mpg
% file nuu.mpg
nuu.mpg: MPEG sequence, v1, progressive Y'CbCr 4:2:0 video, CIF PAL, 25 fps
Finally, we'll fire up ResEdit in Mini vMac. The strings for the error message are part of the "Finder," so we'll edit those. In this case the two message lines are in resource STR##128, strings 11 and 12. More about the other strings later.

When we quit Mini vMac, unmounting the new STB image, we'll need to recompute the checksum and then re-bless the System Folder. Assuming you haven't changed the layout of the folders, changing byte 1119 to 16 ($10) will fix the latter. Then the tool will take the original red ROM dump and the new STB ROM disk image and emit a new 2MB ROM with a corrected checksum ready for use (if you pass -fix16, it will also change that byte for you, but it doesn't do it by default just in case). It will complain if the boot blocks are missing or if the System Folder isn't blessed. Assuming it's happy, burn the new ROM image it generates and fire up the 'Box.

Seems appropriate for hacking a cable network box, don't you think? Showtime/Movie Channel, beware!

The abbreviated "Finder" is the piece doing all the magic here. If you simply replace it with the regular Finder or even a teensy tiny Finder substitute like FaberFinder, the yellow LED never appears, meaning to understand what's going on we'll need to figure out what it's up to.

Unlike the standard Finder, STB Finder is just a regular application (with type and creator codes APPL and fHfM for "Fred Huxham Fred Monroe"). You can even run it from the extracted disk image, whereupon it turns the screen pink, hides the menu bar and pointer, and just sits there until you quit with Command-Q while it presumably waits for the non-existent power button to be pressed. The timeout error message never appears, even if you're Captain Midnight.

There are, of course, a few interesting resources in it. It was left checked out of Projector and ResEdit warns you about this; the ckid resource has the same project and author, and says it's "beta 7 - handles more ways an application can hose itself." (Oh, really?) Accordingly, its (actual) Finder information gives it a version of "1.0ß7, Copyright © Apple Computer, Inc. 1995".

There is an actual menu bar resource for this application, though it's never used, showing the STB Finder's internal name as FredTVApp. If it has any special response to Command-O, however, it isn't evidenced by pressing the combination on an attached keyboard (only Command-Q), and there is no corresponding resource for an "about" dialogue box.

Let's turn to the disassembler and go through the CODE resources now. Only CODE#1 has actual program data. In these and all succeeding extracts, recall that A7 is the 68000 stack pointer, A6 is the frame pointer and A5 is the app-system globals boundary pointer. The resource_dasm disassembler we're using here displays the destination argument first and we will use that convention for new code for consistency. I have fixed up offsets since it got a little confused by the resource layout.

Although there is a fair amount of preamble, here is the main function, which I have pre-annotated. Our ability to understand the code is greatly enhanced by the presence of in-line symbols.

; main 
; start up GUI 
00000548  4E56 0000                link       A6, 0
0000054C  2F03                     move.l     -[A7], D3
0000054E  7600                     moveq.l    D3, 0x00
00000550  7600                     moveq.l    D3, 0x00
00000552  A063                     syscall    MaxApplZone
; Initialize
; set up event handlers            
; InitGraf, etc.                   
00000554  4EB9 0000 07DE           jsr        [0x000007DE]
0000055A  A852                     syscall    HideCursor
; HideMenuBar
0000055C  4EB9 0000 125E           jsr        [0x0000125E]
; HideIt (nuke menu bar selector)  
00000562  4EB9 0000 12B2           jsr        [0x000012B2]
; DrawMPEGStill
00000568  4EB9 0000 15EE           jsr        [0x000015EE]
; EventLoop
0000056E  4EB9 0000 0588           jsr        [0x00000588]
; Cleanup (doesn't do anything)
00000574  4EB9 0000 096A           jsr        [0x0000096A]
0000057A  261F                     move.l     D3, [A7]+
0000057C  4E5E                     unlink     A6
0000057E  4E75                     rts
00000580  846D 6169 6E00 0000      dc.b       "main"

The long and short of it is this was written in a high-level language (most likely C), and the operating system, font and painting operations are regular Macintosh Toolbox A-line traps which the disassembler has kindly filled in for us. That means everything, including the "desktop," draws to the same screen and uses the same calls as any other System 7-compatible application. This phase of the application works on regular System 7 (more about this later on), so we can test our work in Mini vMac instead of burning flash write cycles.

Moving or substantially altering this code in ResEdit has side effects, usually explosive ones. Very carefully and not without a lot of trial-and-error, the first cut was to turn the HideCursor syscall into a nop $4e71, then neuter HideMenuBar and HideIt (since other things call them) by setting their first instructions to rts $4e75.

Next, we need to redraw the menu after the MPEG still is painted but we can't move the jsr DrawMPEGStill up without causing a crash (try it yourself: this is because such branches are actually patched as part of loading the resource into memory), so we'll insert the DrawMenuBar $a937 trap into EventLoop by obliterating the seemingly superfluous clr.w at the beginning (there weren't any spare bytes after the paint in DrawMPEGStill). Here's the rest of the event loop.

; EventLoop
00000588  4E56 FFEE                link       A6, -0x0012
0000058C  426E FFEE                clr.w      [A6 - 0x12]  <<< MARKED FOR DEATH
00000590  6020                     bra        +0x22 /* 000005B2 */
; spin event loop
00000592  554F                     subq.w     A7, 2 
00000594  3F3C FFFF                move.w     -[A7], 0xFFFF
00000598  486E FFF0                pea.l      [A6 - 0x10]
0000059C  4878 001E                push.l     0x1E
000005A0  42A7                     clr.l      -[A7]
000005A2  A860                     syscall    WaitNextEvent
000005A4  101F                     move.b     D0, [A7]+
000005A6  486E FFF0                pea.l      [A6 - 0x10]
; call event handler
000005AA  4EB9 0000 05C8           jsr        [0x000005C8]
000005B0  584F                     addq.w     A7, 4
; wait for global to turn zero: if so, terminate
; this is set by the Quit menu item
000005B2  4A2D FF44                tst.b      [A5 - 0xBC]
000005B6  66DA                     bne        -0x24 /* 00000592 */
000005B8  4E5E                     unlink     A6
000005BA  4E75                     rts
000005BC  8945 7665 6E74 4C6F 6... dc.b       "EventLoop"

In Mini vMac we now have what appears to be a normal, if not particularly useful, application (and no more pink screen), with a regular pointer and menu bar. On the AITB, we get a regular pointer, a black screen, and no menu bar. Eventually the failure text comes up and we crash. But we have a mouse pointer now, so that's a start.

Incidentally, what displays the text is another routine called DrawMessageText, which takes two string pointers and displays them centered in Helvetica in those fixed locations. This is called by multiple routines, but if you check back in that STR# resource, most of the strings it's called to draw are blank and only the error messages are populated. This is good evidence that the red ROM we have was very late in development and possibly saw production use.

It appears that the "pink screen" — a simple solid window, really — is how the hardware decides where to draw the MPEG frame, essentially a Margot Robbie chroma key. For the second cut, we'll put back that clr.w in case it was salient, restore HideMenuBar to spew forth the Pepto-Bismol, and put the DrawMenuBar trap into HideIt (but elide the rest of it as before). That way the menu bar will draw on top of the pink window and should not be obliterated by it. Test run in Mini vMac:

Those changes bring back the pink screen but keep the menu bar and pointer. Selecting the About option just makes it beep at us, by the way. Still, it's likely that this part is only the state of the machine before the power button is pressed, and we want to get the screen on (and not time out and crash), so we need to keep going through the disassembly.

It would seem logical to assume that since everything so far has been Toolbox-based, the signal that the power button was pressed is probably also a regular Toolbox Event. Attaching an ADB keyboard to the STB3 and pressing the Power key doesn't do anything, so we go back to the code. The event handler called by the event loop has typical handlers for mouse down, key down, update and activate events, as well as the "high level" event handler for Apple events, but also a mysterious handler for an application-specific app3Evt (event type 14).

label000006BE: ; app3Evt           
000006BE  4A2D FC76                tst.b      [A5 - 0x38A]
000006C2  6632                     bne        +0x34 /* 000006F6 */
000006C4  0CAA 0000 0115 0002      cmpi.l     [A2 + 0x2], 0x115
000006CC  6628                     bne        +0x2A /* 000006F6 */
000006CE  1B7C 0001 FC76           move.b     [A5 - 0x38A], 0x1
000006D4  2B6A 0006 FC6E           move.l     [A5 - 0x392], [A2 + 0x6]
000006DA  594F                     subq.w     A7, 4
000006DC  2F2D FD34                move.l     -[A7], [A5 - 0x2CC]
000006E0  4267                     clr.w      -[A7]
000006E2  2F3C 0002 001E           move.l     -[A7], 0x2001E
000006E8  7000                     moveq.l    D0, 0x00
000006EA  A82A                     syscall    ComponentDispatch
000006EC  201F                     move.l     D0, [A7]+
; StartTheBootProtocol             
000006EE  4EB9 0000 0A02           jsr        [0x00000A02]
000006F4  6050                     bra        +0x52 /* 00000746 */
000006F6  0C2D 0001 FC76           cmpi.b     [A5 - 0x38A], 0x1
000006FC  661E                     bne        +0x20 /* 0000071C */
000006FE  0CAA 0000 0115 0002      cmpi.l     [A2 + 0x2], 0x115
00000706  6614                     bne        +0x16 /* 0000071C */
00000708  701E                     moveq.l    D0, 0x1E
0000070A  D0AD FC6E                add.l      D0, [A5 - 0x392]
0000070E  B0AA 0006                cmp.l      D0, [A2 + 0x6]
00000712  6408                     bcc        +0xA /* 0000071C */
00000714  3F3C 0002                move.w     -[A7], 0x2
00000718  A895                     syscall    ShutDown
0000071A  602A                     bra        +0x2C /* 00000746 */

Much of the special hardware control is done through the poorly documented ComponentDispatch trap, officially part of the Component Manager (makes sense as QuickTime was its major utilizer and this machine is basically a QuickTime box). Best guess is that it uses the "STB3 Component" at resource thng#48803, though being related to power-on it could also be the "I2C Component" (thng#48798). Here, it checks a global variable (i.e., via A5) and a code word, and if that variable is zero but the code word is 0x115, it calls an internal component (to turn on the screen?) and then calls StartTheBootProtocol (which, completely unexpectedly, starts the remote boot sequence). But if the global variable is one with that same code word, it triggers the ShutDown trap (which forcibly reboots the AITB). All this sounds like what you'd get if the power button were pressed.

The timeout is in DoIdle, which is called within StartTheBootProtocol. We'll shortcircuit that.

; SendPowerUpMessage               
00000A3E  4EB9 0000 0BE8           jsr        [0x00000BE8]
00000A44  3600                     move.w     D3, D0
; SendBootMessage
00000A46  4EB9 0000 0C54           jsr        [0x00000C54]
00000A4C  3600                     move.w     D3, D0
; get current count
00000A4E  A975                     syscall    TickCount
00000A50  201F                     move.l     D0, [A7]+
00000A52  0680 0000 0708           addi.l     D0, 0x708
00000A58  2B40 FD04                move.l     [A5 - 0x2FC], D0
00000A5C  5C4F                     addq.w     A7, 6
00000A5E  6004                     bra        +0x6 /* 00000A64 */
; call DoIdle if A5 - 0x300 is null - see flag notes elsewhere
00000A60  4EBA FF1A                jsr        [PC - 0xE6 /* 0000097C */]
00000A64  4A2D FD00                tst.b      [A5 - 0x300]
00000A68  67F6                     beq        -0x8 /* 00000A60 */  <<< MARKED FOR DEATH
00000A6A  594F                     subq.w     A7, 4
00000A6C  2F2D FD38                move.l     -[A7], [A5 - 0x2C8]
00000A70  2F3C 0000 0703           move.l     -[A7], 0x703
00000A76  7000                     moveq.l    D0, 0x00
00000A78  A82A                     syscall    ComponentDispatch
00000A7A  201F                     move.l     D0, [A7]+
00000A7C  3600                     move.w     D3, D0
00000A7E  3003                     move.w     D0, D3
00000A80  261F                     move.l     D3, [A7]+
00000A82  4E5E                     unlink     A6
00000A84  4E75                     rts
00000A86  9453 7461 7274 5468 6... dc.b       "StartTheBootProtocol"

If we make that beq at $a68 a nop, then as it won't ever branch to the exit point in DoIdle, the function will always exit back to the event loop and thus we'll stay in the event loop forever without timing out. Sounds like it should work!

And, well, it sort of worked. We have a mouse pointer and we have a "desktop." In fact, our call to draw the menu bar has clearly caused something different, as you can now see the typical rounded Mac screen borders which weren't present before. (Notice the gutters: this is from the era of CRT displays, so the displayed desktop is within the safe zone.) The mouse pointer even moves with the mouse, and we don't crash or time out! But we have no menu bar despite explicitly asking to draw it and we patched out the only other function that would disable it, so what gives?

Unfortunately I'm not sure what's going on here, exactly. The ROM System file lacks MDEF and MBDF resources for defining the menu bar and menus, but these resources are present elsewhere in the ROM and don't seem unusually short or weird compared to regular System 7.1. I also couldn't find anywhere obvious that the DrawMenuBar trap was patched into a no-op.

On the other hand, our event handler code is still active: if we press Command-Q, the device restarts as usual. If we patch the code that receives a menu click to make Command-O (menu item 1) the same as Command-Q (menu item 2, i.e., change the instruction to branch to the same spot), then Command-O will also quit and restart the STB. That means that even though we can't see our menu options, we can still activate them. Since there's code in the STB Finder to handle the Apple menu, why don't we make Command-O open something else for us?

To the STB disk image I added the 7.1 Chooser and associated components — since eventually we'll need to mount something over LocalTalk — and a copy of the tiny Finder substitute FaberFinder in the Apple Menu Items folder. We'll pare down their resources later. FaberFinder would be item 4 in this case ("About FredTVApp," then a separator, then the Chooser, then FaberFinder). This is the relevant code in the menu handler.

00000780  0C43 0001                cmpi.w     D3, 0x1
00000784  6608                     bne        +0xA /* 0000078E */
; beep if the first item (About FredTVApp) is selected
00000786  3F3C 0001                move.w     -[A7], 0x1
0000078A  A9C8                     syscall    SysBeep
; and exit
0000078C  6034                     bra        +0x36 /* 000007C2 */
; else handle the rest of the apple menu      
0000078E  594F                     subq.w     A7, 4
00000790  3F3C 0080                move.w     -[A7], 0x80
00000794  A949                     syscall    GetMenuHandle
00000796  205F                     movea.l    A0, [A7]+
00000798  2F08                     move.l     -[A7], A0
0000079A  3F03                     move.w     -[A7], D3
0000079C  486E FF00                pea.l      [A6 - 0x100]
000007A0  A946                     syscall    GetMenuItemText/GetItem
000007A2  554F                     subq.w     A7, 2
000007A4  486E FF00                pea.l      [A6 - 0x100]
000007A8  A9B6                     syscall    OpenDeskAcc
000007AA  301F                     move.w     D0, [A7]+
000007AC  3600                     move.w     D3, D0
000007AE  6012                     bra        +0x14 /* 000007C2 */
; File menu
000007B0  3003                     move.w     D0, D3
000007B2  48C0                     ext.l      D0
; Open (does nothing)
; item 1
000007B4  5380                     subq.l     D0, 1
000007B6  670A                     beq        +0xC /* 000007C2 */
; Quit (this sets the global quit flag)
; item 2
000007B8  5380                     subq.l     D0, 1
000007BA  6702                     beq        +0x4 /* 000007BE */

Since the About item can't be opened on the STB right now anyway, we're going to turn the move.w -[A7],0x01:SysBeep into a bra +0x3c, opcode $603a, so that it still works. That frees up six bytes. We'll make the last two into a moveq.l D3,#4 opcode $7604 and fall through into the routine immediately afterwards that opens a desk accessory, then change the branch for the Open item to hit that moveq. It should then make Command-O open the fourth item on the menu.

We can test this in Mini vMac, and it worked (it opened the second item of the Apple menu after the separator, which happens to be the AppleCD Player). I loaded it onto the AITB and it did nothing — it didn't crash, but it didn't do anything either. In case it would only work with a real desk accessory (the Chooser is), even though OpenDeskAcc in System 7 shouldn't care, I changed it to 3. That worked fine on Mini vMac too, and still not on the AITB. Again, it's not clear if this trap was disabled or altered, or if those apps just plain can't run in this limited environment. More thoughts on that in a little bit.

Do even dialogue boxes work? There are some ALRT and DITL resources in the red ROM, but instead we'll create a simple dialogue box within the STB Finder and have our Command-O hook display that box. Since the Command-O hook already branches to it, we'll just overwrite the desk accessory code above with this hand-assembled snippet and pad it out with nops.

     clr.w -[a7]       ; 4267       ; outparam
     move.w -[a7],#128 ; 3f3c 0080  ; alert 128
     clr.l -[a7]       ; 42a7       ; no filterproc
     Alert             ; a985
     addq.l a7,#2      ; 548f       ; pop outparam
Catch the wave! The OK button responds correctly to RETURN and to the mouse. The background doesn't repaint, but that's solvable (because it's no longer pink, the MPEG still is no longer painted there). Plus, it makes a beep through the stereo outputs, presumably with that ROM snd #1 resource, so sound more or less works fine. Between QuickDraw, audio and some basic support for dialogue boxes at least you could do some sort of basic app with that. It seems the most likely logical resolution for the screen is 640x400, based on experimentation with the dialogue box position.

Still, the Promised Land is to create an AITB ROM that can run arbitrary programs it can download to memory, and the STB ROM disk must clearly do this, or it would never have worked otherwise. To discuss how it worked, it's important to remember that T1/E1 is intrinsically a serial connection: for example, my old residential T1 line was basically a hardwired PPP link over HDSL, and even T1-based frame relay was still just serial data with T-carrier framing. As such, the STB ROM treats the T1 connection like a serial port and executes reads and writes on it directly. AppleTalk is not involved.

Based on the symbols and the call chain by manually walking through the disassembly, the end state is for the local client to receive a complete HFS disk image from the remote server. As part of Initialize in main, the transmit side is setup by ITVInitWriteChannel (note the use of another acronym, ITV, which may have been in use earlier), which calls SerialOpenDrivers and SerialInitialize to handshake with the headend using SerialHandshake. When the power-on event is received, the call to StartTheBootProtocol in the event handler calls SendPowerUpMessage and SendBootMessage, which send messages through ITVWriteBytes to SerialWriteBytes. All messages to and from the cable headend are checksummed ultimately by the routine at mzbBPCalcChecksum, called by VerifyChecksum and WriteChecksum.

After sending the initial startup messages, StartTheBootProtocol falls into a loop repeatedly calling DoIdle, which will maintain a progress bar based on the current tick and call BackChannelDataHandler if data is available to read into the buffer. (StartTheBootProtocol is what we said didn't seem to call WaitNextEvent very much, because it turns out it doesn't.) This handler will send an abort to the headend and reset the boot state if there is a transmission failure, as will any routine where the checksum is wrong.

SendPowerUpMessage sets the first state, to wait for a "size" packet from the headend. Once BackChannelDataHandler assembles a complete packet, this first one goes to SizeMessageHandler; it allocates the requested memory space for the incoming disk image (or aborts) and calls SendReadyMessage which sets the next state, to start receiving data packets. These are routed to DataMessageHandler which stores the packet and calls SendAckMessage, keeping the progress bar updated. Any timeout will also abort the boot process.

SendAckMessage will keep the state pointing to DataMessageHandler as packets arrive until the last one, when it will call GotFinalDataMessage. GotFinalDataMessage sets a global flag to inhibit further calls to DoIdle and calls CreateDiskFromImage to mount the downloaded disk image, which in turn calls LaunchSystemUpdate to run a system update (if there is one) and finally LaunchStartupApp to run the main program. No code signature is obviously involved, meaning it will run anything it gets from the remote server assuming the checksums are all valid. The filenames it looks for appear to come from the DATA#0 resource of the STB Finder, which is copied into memory early during its initialization:

00000000  00 00 00 c7 ff ff ff 44  81 01 00 20 f3 83 b9 4d  |.......D... ...M|
00000010  e5 49 1b 20 6b 44 95 eb  00 88 01 04 01 f5 0e 2e  |.I. kD..........|
00000020  53 54 42 44 69 73 6b 44  72 69 76 65 72 43 95 0c  |STBDiskDriverC..|
00000030  53 79 73 74 65 6d 55 70  64 61 74 65 0a 53 74 61  |SystemUpdate.Sta|
00000040  72 74 75 70 41 20 70 99  0a 53 74 61 72 74 75 70  |rtupA p..Startup|
00000050  44 6f 63 6f 73 3d 4d 61  63 53 54 42 3a 72 76 3d  |Docos=MacSTB:rv=|
00000060  31 2e 20 30 88 3a 63 70  3d 36 38 30 34 30 48 8e  |1. 0.:cp=68040H.|
00000070  0e 2e 53 54 42 44 69 73  6b 44 72 69 76 65 72 43  |..STBDiskDriverC|
00000080  87 09 4d 50 45 47 53 74  69 20 6c a3 09 2e 54 53  |..MPEGSti l...TS|
00000090  44 72 69 76 65 72 00 04  2e 41 49 6e 05 2e 41 4f  |Driver...AIn..AO|
000000a0  75 74 00 04 2e 42 49 6e  05 2e 42 4f 75 74 00 01  |ut...BIn..BOut..|
000000b0  00 00 00 00 28 00 00 00  00 28 00 00 00 00 00 00  |....(....(......|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 67 40  |..............g@|
000000d0  6e 83 8a 42 30 84 83 83  83 83 9b 40 6b d6 bc 88  |n..B0......@k...|
000000e0  40 46 d7 40 c2 f0 f0 b0  90 8e a6 40 44 85 83 8e  |@F.@.......@D...|
000000f0  8e 95 92 83 84 40 57 85  a8 bc f8 b3 8c b4 8b 9f  |.....@W.........|
00000100  b2 9e ec 99 ec 97 ec b4  98 86 8b a1 a6 85 89 a0  |................|
00000110  e6 af e0 9b 88 a0 b6 ab  aa 8b 99 90 a1 42 13 7f  |.............B..|
00000120  a4 40 48 a0 95 f4 94 bc  94 88 89 40 ad d5 bb fa  |.@H........@....|
00000130  db fa 40 b4 84 40 b2 40  81 f5 b7 f5 9b f8 95 b4  |..@..@.@........|
00000140  bc f0 f0 f1 00 00 00 00                           |........|

I'm not sure where those spurious spaces came from, but it appears to run SystemUpdate, if it exists, then launches one of two files, which appear to be either StartupApp or StartupDoc (again, based on what's present). The same driver .STBDiskDriver that handles accessing the ROM disk likely handles the RAM disk, which is very economical. Also note that the strings in this resource indicate the unit identifies itself as a MacSTB 1.0 with a 68040, which seems to be sent by the initial message routines, and the presence of the string for MPEGStill, which is what DrawMPEGStill opens and references.

If you label all the STR# strings in the STB Finder with numbers, you should be able to observe the boot stages as most of them call DrawMessageText, just with empty strings. I reverted our changes to the STB Finder and just made the resource change so we'd have a "clean" show. Here's the beginning:

And the end:
We never get past the beginning, of course, so we only see the Alpha and the failed Omega.

The actual section of code that triggers execution of the downloaded apps, DoALaunch, uses the Toolbox Launch trap at $a9f2. Notably it generates a MultiFinder extended launch param block but uses an unusual fixed set of launch flags (see the SIZE resource) set to $4800, which designate an application that understands suspend and resume but is not MultiFinder-aware. As such it could not run arbitrary classic Mac applications even if the rest of the operating system features were present; it can only run ones coded to work with this limited environment, even though such applications should also work on vanilla System 7 modulo any specialized calls to the AITB hardware drivers. It might be possible to generate an application that could boot something else in the way that things like the Booter application start NetBSD/mac68k, but it's not clear if this could actually boot another version of Mac OS entirely, at least not without including a lot of extra resources that would ordinarily be present in a typical Toolbox ROM.

And that's why we have such an odd hybrid STB Finder where most of its GUI code does nothing on the real hardware. My best guess is that the development systems booted a modified full System 7.1 rather than the bowdlerized mini-System in the red ROM, including all the thngs and other necessary STB-specific components (such as the driver for the video card I don't have). It is not obvious that the red ROM is capable of booting any operating system other than itself, which explains why most of the few AITBs in collector hands have green Quadra 605 ROMs: the Q605 ROM has a normal Toolbox and will boot a System Folder from a SCSI volume, or at least others other than mine will, and is compatible enough with the AITB to at least drive the on-board NCR SCSI controller until it can load the other INITs for the unique hardware (the red ROM already has this support). Such a setup would be perfectly cromulent for a developer machine and the surviving units probably mostly came from those settings. That said, whatever the circulating stbextensions folder does, it doesn't seem to be enough to enable the other AITB hardware components — though it may simply be incomplete or the bootable OS had other changes.

Either way, given the STB Finder is "just" a regular application, you can run it and the applications it triggers from a regular System 7 installation once you've got the OS booted on an AITB, but now having done so you can test all the other AITB-specific pieces. If you try to run the STB Finder on a regular Mac and forge that event code to force a power-on event, you'll crash, shut down or do nothing because the other needed system components (and hardware) are missing. The system update functionality is particularly interesting, though as there are no known surviving examples of any of the downloaded applications we don't know exactly what they did or how. It can't be excluded that the system update would have actually reflashed the onboard ROM through an unknown mechanism, but there's no obvious facility on the logic board to do so, and over the unit's short lifetime no system update may ever have been deployed.

Let's tie it all together and make a Hello World ROM that you could potentially use as a jumping off point for your other applications. I'm not making this red ROM dump available publicly to avoid the litigious wrath of the Cupertino mothership, but if you have or get a red ROM dump, you can try it. Set up Mini vMac running at least System 7.1 (I use it in Macintosh II mode with System 7.5.5), and, of course, get a flash ROM SIMM and programmer. You'll need ResEdit as well. Note these steps should work with SheepShaver or Basilisk II as well, but those emulators may destroy the STB image's bootblocks and you'd have to restore them afterwards.

Extract the disk#0 resource from the ROM using our resource walker (something like perl RED.rom disk 0 will create a disk-0.dump file). Name it something like stb.img. Start Mini vMac with both your System 7 boot drive and the STB image on the command line so that they are mounted simultaneously (don't worry, the emulator won't try to boot from the STB image if it's listed second).

Back up the Finder from the STB image and then drag it to ResEdit, which will say it was checked out read-only; you can ignore this. Remove the single ckid resource if it annoys you. Optionally, in STR# 128 change strings three and four to your desired startup message if you like, and create a new MPEGStill file using ffmpeg and mpegdemux and ensure its type and creator are MPEG and mMPG.

For the actual "proof of hack" dialogue box, add the DITL and ALRT resources for your alert dialogue box to the STB Finder; the code below assumes the ALRT resource is numbered 128. Open the STB Finder's CODE resource 1 and in the hex editor make the following changes:

  • Remove the Toolbox call to HideCursor at offset $055a by changing the opcode to $4e71.
  • Add a new handler for our alert routine at offset $0786 by changing the three opcodes at that location to $4eba $1810 $4e71.
  • Change the branch at $07b6 to point to the new subroutine call by making it $67ce.
  • Disable the timeout by changing the opcode at offset $0a68 to $4e71.
  • Neuter the call to HideIt at offset $12b6 by changing the three opcodes starting at that location to $a937 $4e5e $4e75.

Finally, add these opcodes to the end, starting at $1f98 (the offset after the end of the resource).

1f98: 4e56 0000 4267 3f3c
1fa0: 0081 42a7 a985 548f
1fa8: 4e5e 4e75

Close and save the modified Finder on the STB disk image and shut down Mini vMac. If you changed the folder structure of the ROM, you will need to manually rebless the System Folder with a hex editor and then merge the STB image back into the ROM with the splicer (something like perl RED.rom stb.img NEWRED.rom). If you didn't change the folder structure, then pass the -fix16 argument and the splicer will bless the System Folder for you.

Burn the new ROM to your flash ROM SIMM, install it into the AITB, connect an ADB keyboard and mouse, and turn on the AITB's rear power switch. When the LED in the front turns yellow, press the power button. Press Command-O after startup to open the dialogue box.

The AITB is now your own. Things to do: figure out how to branch to separate code immediately after power-on in the app3Evt handler at $06be (so far I get nothing but crashes trying to muck around there), figure out how the CD-ROM support works with the red ROM, and figure out a means to transfer an application disk image into memory with the real serial port (the AITB can use a serial printer, so there is at least some support for driving the Zilog SCC). And things I need to do: figure out what fuse I opened, or something, to make my own AITB not boot from SCSI. But now this exceptionally rare Apple machine should be much less of a mystery to you.

I would love to hear from you if you were involved in this machine's development (or can even just identify the last picture in our image composite). If you'd prefer not to post a public comment, you can E-mail me at ckaiser at floodgap dawt com.

The code we put together to help walk and modify the red ROM dump is available on Github.

No comments:

Post a Comment

Comments are subject to moderation. Be nice.