System Files:QFILEIML

From Try-AS/400
Revision as of 19:37, 8 August 2026 by Friedkiwi (talk | contribs) (Correct the SP firmware section: SP xxx are link-table module names, not component tags; fix family counts (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

Offset Contents
0x000 Magic C9 D4 C4 F1, which is IMD1 in EBCDIC, followed by a short and largely unexplored header
0x200 Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers
0x400 Directory header: a four-byte preamble, the literal string Directory., two zero bytes, then a 16-byte build label
0x420 The directory: a run of 32-byte LID records
varies Terminator record, identifier 0xC5D5C440 (END  in EBCDIC)
0x5400 Payload area

The first sixteen bytes of the file are:

00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000

The banner at 0x200 reads, in EBCDIC:

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

The three seven-digit numbers are LIC product identifiers, and the same three appear in QFILEMCD. The build label at 0x410 is v4r4m01204.0.03, likewise identical between the two files, which is a convenient way to confirm that a given QFILEIML and QFILEMCD came off the same media.

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 QFILEIML. It is a load-source LBA, describing where the payload sits on the installation medium, and it has no useful meaning inside the container file.

Reading it as a file offset is superficially attractive and definitively wrong. Doing so on this 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.

This is exact rather than approximate. The lengths sum to 158,723 blocks against a 158,765-block file, placing the start of data at block 42 — that is, 0x5400, immediately past the directory terminator — and the payloads then tile to the final byte of the file with nothing left over.

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.

Module headers

Each of these images is not a monolithic firmware blob but a collection of linkable modules, each introduced by a header with the EBCDIC eyecatcher PGPM (D7 C7 D7 D4). There are 119 such headers in the container. The useful fields are:

Offset Contents
+0x00 PGPM eyecatcher
+0x04 A LID identifier — but see the caveat below
+0x24 EBCDIC version string, e.g. 0100
+0x30 8-byte build identifier, e.g. AJSFGVB3
+0x54 8-byte name of the module this header defines
+0x60 Slot table, 4-byte values
+0xC0 Import table: 12-byte entries, each an 8-byte name and a 4-byte linkage slot, terminated by eight EBCDIC F characters

Note! Strings such as SP MOPT1, SP SPCI3 or SP WT are module names in a link table, not feature or capability tags. An earlier version of this article described them as component tags whose differing sets indicated capability tiers across the hardware range. That reading was wrong: the sets differ because different modules import different things.

Worked example, from the header at +0x59C of LID A07008C2: build AJSFGVB3, defines SP SB, and imports SP SPCI1 through SP SPCI5 and CUANSI, with the import table running to its terminator at +0x1B4.

Both families share a common utility layer, which is why their vocabulary overlaps: CUANSI, CUCONV, CUIO, CUMEMORY, CUMISC and CUSTO, plus SRASCOMN for RAS common code.

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