System Files:QFILEIML

From Try-AS/400
Revision as of 20:46, 8 August 2026 by Friedkiwi (talk | contribs) (Replace the file-size payload-start rule with one derivable from the directory alone (via update-page on MediaWiki MCP Server))
Jump to navigation Jump to search

QFILEIML is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine's loadable microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic IMD1 and is a container of LIDs.

The companion file QFILEMCD holds SLIC proper, via a directory called COPYDIR. Both files use the same 32-byte LID directory record, and a record present in both is byte-for-byte identical, so the two are two views of one packaging scheme rather than two unrelated formats.

The name is not documented by IBM as far as is known here. IML almost certainly stands for Initial Microprogram Load — the phase in which the machine's microcode is brought up, before OS/400 itself exists — which matches the file's contents. Treat the expansion as an inference.

Everything below was determined by inspection of a V4R4 image and should be read as applying to that release. The figures quoted are from a single QFILEIML of 81,287,680 bytes (77.5 MiB), build label v4r4m01204.0.03.

File layout

The layout is not at fixed offsets. It is carried in the header, and it differs between releases — a decoder that assumes the V4R4 offsets will read a V7R2 container as having no entries at all, without reporting an error.

The field at +0x08, low 24 bits, is the offset to the Licensed Internal Code banner. The directory header sits at exactly twice that offset, its records 0x20 further on, and the build label at header +0x10.

Release +0x08 Banner Directory header Records Build label
V4R4 ff000200 0x200 0x400 0x420 v4r4m01204.0.03
V7R2 ff000800 0x800 0x1000 0x1020 v7r2m00000.0.00

So the general layout is:

Offset Contents
0x000 Magic C9 D4 C4 F1, which is IMD1 in EBCDIC
0x008 Low 24 bits: offset to the banner. The rest of the header is not understood
banner Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers
banner × 2 Directory header: a four-byte preamble, the literal string Directory., two zero bytes, then a 16-byte build label
banner × 2 + 0x20 The directory: a run of 32-byte LID records
varies Terminator record, identifier 0xC5D5C440 (END  in EBCDIC)

The first sixteen bytes of a V4R4 container are:

00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000

and of a V7R2 one:

00000000: c9d4 c4f1 0000 0000 ff00 0800 0010 0000

The banner reads, in EBCDIC:

LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...

The seven-digit numbers are LIC product identifiers, and the same ones appear in QFILEMCD. The build label is likewise identical between the two container files from the same media, which is a convenient way to confirm that a given QFILEIML and QFILEMCD belong together.

The field at +0x0C differs between the two samples (00e00000 against 00100000) and is not understood. Two samples are not enough to fit it.

The directory

The directory begins at 0x420 and runs, in this image, for 632 records before the END  terminator at 0x5320. The record layout is documented at Data Structures:LID and is not repeated here.

Of the 632 records:

  • 341 carry the compressed flag.
  • 631 name an SLS staging address in the FFFFFFFFxx band. Exactly one does not: LID 80900818 stages at 000000024A 000000.
  • 7 have payloads that are themselves runs of LID records — see Directory extents below.

Payload addressing

Note! This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.

The offset field in each record is not an offset into the container. It is a load-source LBA, describing where the payload sits on the installation medium, and it has no useful meaning inside the file.

Reading it as a file offset is superficially attractive and definitively wrong. Doing so on a V4R4 image yields 608 overlapping extents out of 632, a maximum extent of 34,550 blocks against a 158,765-block file, and a minimum offset of block 3, which lands inside the header. That the lengths happen to sum to approximately the file size is a coincidence and should not be taken as confirmation.

The actual rule is simpler: payloads are stored sequentially, in directory order, immediately after the directory, each one length blocks long. There are no gaps and no padding between them.

Payloads begin at the next 512-byte block boundary after the directory terminator. That is block 42 for the V4R4 sample and block 69 for the V7R2 one. This rule needs only the directory, so it also works on a container embedded in a larger image — an install ISO, for instance — where the file size is not a meaningful quantity.

An older formulation, file size in blocks minus the sum of all lengths, gives the same answer for a standalone file and is a useful cross-check: on the V4R4 sample the two agree exactly, and the implied container size matches the real file size to the byte at 81,287,680. But it cannot be used on an embedded container, so prefer the terminator rule.

To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.

Contents

Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit stwu r1,-x(r1) prologues versus 64-bit std stores:

Population Count Identification
32-bit PowerPC 75 stwu prologues present, no std at all
64-bit PowerPC AS (SLIC) 210 std present, no stwu at all
Neither 347 Compressed payloads, data, tables, and directory extents

The split is clean — no payload shows both — which is what makes the heuristic trustworthy. The 32-bit population is the interesting one: the main processor of these machines is 64-bit PowerPC AS, so 32-bit code in this file is by definition destined for something else. That is the IOP, adapter and service processor microcode.

Service processor firmware

LID 80900702 is service processor Licensed Internal Code: 128 KiB, stored uncompressed, staged at SLS FFFFFFFF9A 001000. Its EBCDIC strings include a 9400 Licensed Internal Code banner and a 1998 copyright, and its code is unambiguously 32-bit.

This confirms a long-standing claim in the trade press that AS/400 service processor firmware is loaded from the load source rather than residing wholly in flash on the card. As the rest of this section shows, that turns out to be only half true.

About 30 payloads carry an AJS build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry AJG identifiers and are I/O offload (MFIOP) code instead; several of those carry an ATM marker, i.e. ATM networking, which is not something a service processor does. The two families are mostly disjoint but not perfectly: at least one payload contains both identifiers.

What is not in the file

Notably, the service processor's own supervisor is absent. Two independent lines of evidence agree on this.

From the instruction stream. All payloads were searched for rfi (0x4C000064), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural 0x100, 0x200 and subsequent offsets of every 4 KiB boundary. Across 4.1 MB of service-processor code there is not one rfi, and no payload has a vector table. Privileged operations are almost as scarce: six instructions of the mtmsr family and four cache or TLB operations in the whole set.

Consistent with that, LID 80900702 begins mid-function, with a function tail rather than an entry point, and manipulates no privileged state at all — only LR, CTR and XER are touched. It does contain 31 sc supervisor calls.

From the link tables. As described above, the numbered module names are imported by many modules and defined by none. The code that provides them is therefore not on this medium.

The conclusion is that the service processor runs a resident supervisor of its own, held in flash on the card, and that this file supplies only loadable task modules that sit on top of it. That is consistent with the hardware — the operator panel carries its own flash, and SLIC has an explicit message for instructing the service processor to IPL itself.

The supervisor call interface

Since the supervisor itself is absent, the sc instructions are the entire visible boundary between these modules and the firmware they run on. Across the family there are 668 supervisor calls using just 9 distinct call numbers, with the number in r0 and arguments from r3:

Call Count Observed arguments
0x020C 262
0x0208 131 r3 = 0x16 in every instance
0x03A4 106 r3 = 0x64, r4 = 5; unique to one module
0x0358 r3 is one of exactly three values: 0x83010000, 0x83020000, 0x83030000

The first two are the interesting pair: 0x0208 occurs exactly half as often as 0x020C, and always on the same resource number, which is the signature of an acquire/release pair around a critical section. The 0x0358 window is the only region passed explicitly to a supervisor call, which is what registering or mapping a device or shared-memory window looks like.

Beyond that the call numbers cannot be decoded, because the code that implements them is not on this medium.

A caution about what this firmware does

It is tempting to assume this firmware covers the obvious service-processor duties — power control, thermal and fan management, SPCN, driving the panel and its LCD, VPD storage, error logging and SRC posting. No such claim is supported by this file.

These modules contain almost no descriptive text. The complete inventory of readable strings is the Licensed Internal Code banner, the copyright boilerplate, the EBCDIC-to-ASCII translation tables, and the PGPM link names. A search for the entire relevant vocabulary — POWER, FAN, THERMAL, SPCN, VPD, PASSWORD, SECUR, SERIAL and more, in both EBCDIC and ASCII, over every byte — returns nothing in any service-processor module. The same vocabulary is present elsewhere in the container, but only inside SLIC payloads.

So the honest position is that the functional surface visible here is nine supervisor call numbers into firmware nobody has. What the service processor actually does is implemented on the other side of that boundary.

One bound on that negative: readable code averages about 46 % of 1 KiB blocks across these images, and one 119 KiB payload is entirely opaque. The supported statement is that nothing is visible in the readable portion, not that nothing exists.

Reading the dependency graph

Because every module declares what it defines and what it imports, the link tables can simply be read off as a dependency graph — which is more informative than any amount of disassembly, and is the main reason the PGPM header is worth knowing about.

Doing so reveals a clean pattern. The numbered names — SP SPCI1 to SPCI5, SP MOPT1 to MOPT9, SP MOPD1 — are imported by many modules and defined by none. The lettered members of the same families — MOPTA, MOPTB, MOPTC, MOPD2 — each import their immediate predecessor and are present as real modules.

The natural reading is that numbered names are resident firmware on the card and lettered ones are downloadable extensions layered on top. Which is exactly what the next section establishes by a completely independent route.

Caveat. The LID identifier at +0x04 of a PGPM header frequently disagrees with the container LID that the sequential payload layout assigns to that region. Most of these values are valid LID identifiers from the directory, and in one region a run of 21 consecutive modules is spaced exactly by the directory lengths of the LIDs they name. Either the layout is displaced there, or modules are stored under a delivery LID distinct from their own. Findings about module contents are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.

What is not in the file

Notably, the service processor's own supervisor is absent. All 632 payloads were searched for rfi (0x4C000064), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural 0x100, 0x200 and subsequent offsets of every 4 KiB boundary. Exactly one payload contains a single rfi in 289 KiB, which is a data coincidence, and no payload has a vector table.

Consistent with that, LID 80900702 begins mid-function, with a function tail rather than an entry point, and manipulates no privileged state anywhere: no mtmsr, no segment or TLB or cache operations, and only LR, CTR and XER touched. It does contain 31 sc supervisor calls.

The conclusion is that the service processor runs a resident supervisor of its own, held in flash on the card, and that this file supplies only loadable task modules that sit on top of it. That is consistent with the hardware — the operator panel carries its own flash, and SLIC has an explicit message for instructing the service processor to IPL itself.

Directory extents

Seven payloads are not data but further runs of 32-byte LID records, largely duplicating entries from the root directory byte for byte. The two largest hold 294 and 133 records. They appear to be indexes rather than nested containers, and a tool walking this file should recognise them so as not to mistake an index for a firmware image. A payload whose first few records parse as plausible LID records, with identifiers matching known LIDs, is an extent.

Compression

341 of the 632 payloads are flagged compressed. The codec is the LZW variant used throughout SLIC and is described at Data Structures:LID#The compressed flag. It has not been needed to read the service processor firmware, which is stored plain, but it stands between the reader and roughly half the file.

Tooling

No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:

  1. check the IMD1 magic at offset 0;
  2. read 32-byte records from 0x420 until an identifier of 0xC5D5C440 or zero;
  3. compute the payload start as file size in blocks minus the sum of all lengths, rather than trusting the offset field;
  4. lay payloads out sequentially in directory order.

Step 3 is what makes extraction correct, and it is worth asserting: if the computed start is not 42 on a V4R4 image, something has been misread.

Open questions

  • The meaning of the header bytes at 0x0040x1FF, and of the four-byte preamble before Directory..
  • The meaning of most LID identifier families.
  • Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.
  • Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.
  • Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.

See also

Weblinks

  • MC Press Online, which carries older documentation describing service processor microcode as being loaded from the load source

Footnotes