-
Notifications
You must be signed in to change notification settings - Fork 0
Theory ARC
This page owns: the firmware standard Windows NT expects on a non-x86 machine, and every place this machine does not have one.
ARC is the Advanced RISC Computing specification. For our purposes it is simply this: the set of things NT's PowerPC loader assumes the firmware will do for it. Understanding ARC is understanding what NT is asking for, which is the only way to understand why the answers have to be manufactured here.
ARC came out of the early-1990s effort to make RISC workstations run shrink-wrapped operating systems. It standardises four things:
- a configuration tree describing the hardware,
- a firmware vector table of functions a loaded program can call,
- a set of environment variables saying what to boot and from where,
- NVRAM to keep those variables in.
Windows NT's MIPS, Alpha and PowerPC ports were all written against it. On the PowerPC side that meant PReP machines from IBM and Motorola, whose firmware provided ARC natively.
NT does not treat ARC as optional or as one of several possibilities. Its loader has no hardware probing to fall back on: if the firmware cannot answer, the boot stops.
A tree of components, each with a class, a type, an identifier string and optional configuration data. NT's loader walks it to learn what exists, and the kernel later converts it into the registry's hardware description.
On this machine the veneer builds one that looks like this (abridged):
device-tree class System ← the root, and its Identifier
PowerPC-604 class Processor
Cache, Cache
memory class Memory
multi(0) class Adapter ← the first PCI bus
scsi(0) → cdrom(0) → fdisk(0)
scsi(1) → disk(0) → rdisk(0)
net(0), serial(0), serial(1), key, point, video
multi(1) … multi(3) ← the second bridge and two more
Two details from this tree have had outsized consequences.
The root's Identifier is what Setup matches a HAL against. Here it is device-tree — the
Open Firmware root node's name, faithfully converted — and it matches nothing in NT's table, so
Setup falls back to asking the user.
→ How Setup chooses a HAL
Identifier strings on devices decide which drivers bind. The SCSI controllers were originally reported with a model string NT did not recognise, so no miniport claimed them and the machine had no disk. Eleven patched bytes fixed it — the ledger, row 5.
ARC names a device by the route to it:
multi(0)scsi(1)disk(0)rdisk(0)partition(2)
│ │ │ │ └── partition 2
│ │ │ └── logical unit
│ │ └── the disk
│ └── the second SCSI controller
└── the PCI bus
Anything after the device part is a file path:
multi(0)scsi(1)disk(0)rdisk(0)partition(1)\os\winnt40\osloader.exe
These strings appear everywhere — in the environment, in the loader's arguments, in NT's registry,
and in \ArcName\ symbolic links inside the running system. Being able to read one at a glance
saves a lot of time.
A table of function pointers the firmware publishes and a loaded program calls. The useful ones here:
GetPeer, GetChild, GetParent, GetComponent
|
walk the configuration tree |
GetConfigurationData |
a component's resource list |
Open, Close
|
a device or a file |
Read, Seek, Write, GetReadStatus
|
I/O on an open handle |
GetFileInformation |
size and attributes |
GetEnvironmentVariable, SetEnvironmentVariable
|
the environment |
GetMemoryDescriptor |
walk the memory map |
GetTime, GetRelativeTime
|
the clock |
Halt, PowerDown, Restart, Reboot
|
ending things |
The entries are at fixed indices in the table, which is how a loader compiled years earlier calls a firmware written later.
On this machine every one of them is implemented by the veneer on top of Open Firmware's client interface. When NT's loader reads a sector, the chain is:
OSLOADER's FAT reader → ARC Seek + Read → the veneer → OF client interface → disk
The variables NT's loader needs, with the values this machine uses:
| Variable | Example | Who reads it |
|---|---|---|
SYSTEMPARTITION |
multi(0)scsi(1)disk(0)rdisk(0)partition(1) |
the loader; Setup |
OSLOADER |
…partition(1)\os\winnt40\osloader.exe |
the firmware, to find the loader |
OSLOADPARTITION |
…partition(2) |
the loader, for the OS |
OSLOADFILENAME |
\WINNT |
the loader |
OSLOADOPTIONS |
NODEBUG |
the loader |
LOADIDENTIFIER |
Windows NT Workstation Version 4.00 |
the boot menu |
AUTOLOAD, COUNTDOWN
|
YES, 5
|
the boot menu |
LASTKNOWNGOOD |
FALSE |
the loader |
CONSOLEIN, CONSOLEOUT
|
multi(0)serial(0)line(0) |
everything |
Read the first five together and the design is clear: the firmware finds the loader on the system partition, and the loader finds the operating system on a possibly different partition. That separation is why a system partition exists at all.
On a real ARC machine the environment lives in NVRAM, written by the firmware's own setup utility, and it survives a reboot. That is the whole point: you install NT, it records where it put itself, and the machine can start it again.
This machine has no ARC NVRAM. Open Firmware has its own nvram, in its own format, owned by Apple's firmware; nothing translates between the two. So on this machine the ARC environment is plain memory, and a reboot loses every variable in it.
The consequences run right through the project:
- Setup writes the boot configuration correctly, through the HAL — and the restart loses it.
- Booting an installed system therefore requires injecting the environment from outside before the loader asks for it.
- The HAL synthesises
SYSTEMPARTITIONfrom the loader's own disk list, because otherwise Setup refuses to start — which is policy in the wrong place, and known to be.
Those are ledger rows 11, 12 and 16, and together they are probably the single most valuable outstanding piece of work: an nvram-backed environment store is what stands between "boots under a test rig" and "boots". → Booting the installed system
ARC machines ship with a firmware utility — ARCINST on many of them — that partitions a disk
and creates the system partition: a FAT partition holding the loader, which the firmware can
read before any NT filesystem exists.
NT's Setup will not begin without one. It does not create it; it expects the firmware vendor's tool to have done so.
This machine has no such tool, so the disk has to arrive already partitioned. That is what
tools/mkarcdisk.py
does — a plain MBR and plain FAT16 partitions, nothing machine-specific.
→ Preparing disks
| ARC expects | This machine has |
|---|---|
| A configuration tree | Open Firmware's device tree, converted by the veneer |
| A firmware vector table | the veneer, over Open Firmware's client interface |
| An environment in NVRAM | RAM, lost on reboot, injected from outside |
ARCINST to prepare a disk |
mkarcdisk.py, run on the host |
| A machine identifier NT recognises |
device-tree, which matches nothing — hence a patched TXTSETUP.SIF
|
Every row of that table is a place where something had to be built, and four of the five are still imperfect.
- The veneer — the implementation of rows 1 and 2 above.
- The NT boot chain — what consumes all of this.
- Reference: ARC environment variables — the full table.
- Open Firmware — what is underneath.
Corrections welcome — this wiki is edited directly, so nothing here has had a review. Repository · STORY.md · GPL-2.0-only
Start here
Theory
- Why NT on a Power Mac is hard
- Open Firmware
- ARC
- The veneer
- The NT boot chain
- The HAL contract
- The NT PowerPC ABI
- Little-endian PowerPC
- How Setup chooses a HAL
- The NT video stack
Machines
Emulator
- Getting Granny Smith
- Media you must supply
- Building the HAL
- The boot floppy
- Preparing disks
- Running text-mode Setup
- Capturing the installed image
- Booting the installed system
- Iterating on the HAL
- Checkpoints and deltas
- Making an OEM CD (retired)
Real hardware
Debugging
- The emulator shell
- Reading NT binaries
- Decoding a bugcheck
- When your instrumentation lies
- Debugging recipes
Reference
- HAL exports
- ARC environment variables
- The veneer's VrDebug bitmask
- Veneer patch catalogue
- Address and interrupt map
- Error codes seen
Project