<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://try-as400.pocnet.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Friedkiwi</id>
	<title>Try-AS/400 - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://try-as400.pocnet.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Friedkiwi"/>
	<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/wiki/Special:Contributions/Friedkiwi"/>
	<updated>2026-08-15T02:57:13Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1788</id>
		<title>Reverse engineering SLIC</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1788"/>
		<updated>2026-08-13T20:34:31Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Add a section on decoding conditional branches (BO/BI, and two disassembler rendering traps), and two traps: decode branches from the raw word, and a field the machine rebuilds at startup is an output (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Reverse engineering &#039;&#039;&#039;SLIC&#039;&#039;&#039; — the Licensed Internal Code below the Machine Interface — is mostly a problem of turning addresses into names and getting bytes off the machine. This article collects the techniques that work, in the order you would actually use them, and the traps that cost the most time.&lt;br /&gt;
&lt;br /&gt;
It assumes access to a machine&#039;s DST or SST service tools, and installation media or a SAVSYS for offline work.&lt;br /&gt;
&lt;br /&gt;
== Start with the machine&#039;s own link map ==&lt;br /&gt;
Before writing any tooling, get the &#039;&#039;&#039;SLIC link map&#039;&#039;&#039; from the machine. It is reached through Display/Alter/Dump and can be printed to a spooled file, then exported.&lt;br /&gt;
&lt;br /&gt;
The printed format is one row per module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NICKNAME    ADDRESS(10+6)   PART NAME    VERSION RELEASE  REL DATE/TIME  INST DATE/TIME&lt;br /&gt;
###FLITE    FFFFFFFFF4 C29820   SRVC_MACRO_FLIGHTLOG   0007 0400 20190217 094024 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A V7R4 machine yields around 21,000 distinct modules. This single artefact answers &amp;quot;what is at this address&amp;quot; and &amp;quot;where is this module&amp;quot; authoritatively, for that machine, and it is the first thing to obtain.&lt;br /&gt;
&lt;br /&gt;
Two properties make it more useful than it first appears:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The spacing between consecutive entries equals the module&#039;s text length.&#039;&#039;&#039; Verified against the lengths &#039;&#039;Find LIC Module&#039;&#039; reports — exact matches. So the map gives extents as well as bases, which means any address can be resolved to a module &#039;&#039;and&#039;&#039; an offset within it.&lt;br /&gt;
* &#039;&#039;&#039;Module names are stable across PTFs; addresses are not.&#039;&#039;&#039; Look modules up by name whenever possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Part names are upper-cased in the printout but the &#039;&#039;Find LIC Module by name&#039;&#039; panel is &#039;&#039;&#039;case-sensitive&#039;&#039;&#039;. &amp;lt;code&amp;gt;IoHriTaggedVpd&amp;lt;/code&amp;gt; resolves; &amp;lt;code&amp;gt;IOHRITAGGEDVPD&amp;lt;/code&amp;gt; does not. Take the spelling from the on-screen display, not the print.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Getting bytes off the machine ==&lt;br /&gt;
Display/Alter/Dump can print a storage range to a spooled file. Exported as PDF and run through &amp;lt;code&amp;gt;pdftotext -layout&amp;lt;/code&amp;gt;, each line is an address and 32 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   FFFFFFFFC5 943160     3C40CC4DFBC1FFF0 FBE1FFF87C0802A6   F8010028F821FF01  3C000010F8010008&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The formatter &#039;&#039;&#039;collapses repeated lines&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        127 LINES    FFFFFFFF84 11B020   TO   FFFFFFFF84 11BFE0   SAME AS ABOVE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A naive parser silently sees a fraction of the data — in one case 44&amp;amp;thinsp;% of a 1&amp;amp;thinsp;MiB region — and reports no error. Any parser must expand these runs.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dumping a whole module at once is usually better than dumping the function you think you want: module extents are known from the link map, and the surrounding code frequently answers the next question.&lt;br /&gt;
&lt;br /&gt;
== Addresses ==&lt;br /&gt;
An SLS address is a &#039;&#039;&#039;40-bit segment identifier and a 24-bit offset&#039;&#039;&#039;, which is exactly how the &#039;&#039;Specify Address&#039;&#039; panel splits it, so segments are 16&amp;amp;thinsp;MiB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probe before dumping.&#039;&#039;&#039; Entering an address in an unmapped segment returns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
80 exception, segment does not exist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a free existence oracle. But probe the &#039;&#039;&#039;address you actually care about&#039;&#039;&#039;, not offset zero of its segment — segments are sparsely populated, and offset 0 being unmapped says nothing about the rest. A segment can be mapped at &amp;lt;code&amp;gt;0x010000&amp;lt;/code&amp;gt; and raise the exception at &amp;lt;code&amp;gt;0x120000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For a mapped address, the &#039;&#039;&#039;ADDRESSINFO&#039;&#039;&#039; Advanced Analysis command reports the page-directory entry and hardware page-table entries, confirming backing and page size.&lt;br /&gt;
&lt;br /&gt;
=== Runtime and staged addresses differ ===&lt;br /&gt;
The same module may appear at one address in the link map and another as its runtime text. Where these differ, &#039;&#039;&#039;module-relative offsets are stable&#039;&#039;&#039;: a symbol at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the staged image is at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the runtime image. Deriving runtime addresses this way works reliably; assuming a constant delta between two images does not.&lt;br /&gt;
&lt;br /&gt;
== Names from the code ==&lt;br /&gt;
Two structures let a container image be turned into a link map offline.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Traceback trailers.&#039;&#039;&#039; Every compilation unit ends with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; eyecatcher (&amp;lt;code&amp;gt;E3C2E3C2&amp;lt;/code&amp;gt;) followed by a pointer to a descriptor. A trailer covers a whole compilation unit, so it localises rather than pinpoints — and a forward scan for &amp;quot;the next trailer&amp;quot; will silently attribute a &#039;&#039;later&#039;&#039; function&#039;s name if the target has no trailer of its own.&lt;br /&gt;
* &#039;&#039;&#039;Link-loader descriptors.&#039;&#039;&#039; Richer: one per procedure, with the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Names beginning &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ mangled symbols.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Two mistakes here are expensive. First, &#039;&#039;&#039;do not require the entry address to fall inside a segment the container carries&#039;&#039;&#039; — runtime-only segments exist, and filtering on containment silently drops every module in them. Second, the name is not always at a fixed offset from the descriptor; scanning for the longest identifier run within the descriptor is more robust than assuming one.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module metadata ==&lt;br /&gt;
&#039;&#039;Find LIC Module&#039;&#039; reports, for any address: module name, nickname, compile and link/load timestamps, version and release level, &#039;&#039;&#039;PTF level&#039;&#039;&#039;, and the text, data and BSS extents plus the TOC address.&lt;br /&gt;
&lt;br /&gt;
The same record exists on media, anchored by the EBCDIC PTF-level string (&amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; for an unpatched module):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+0x00  PTF level     7 bytes    &amp;quot;SYSBASE&amp;quot;&lt;br /&gt;
+0x07  version       4 bytes    &amp;quot;0007&amp;quot; = V7&lt;br /&gt;
+0x0B  release/mod   4 bytes    &amp;quot;0400&amp;quot; = R4M0&lt;br /&gt;
+0x0F  nickname      8 bytes&lt;br /&gt;
+0x27  build id      7 bytes    &amp;quot;AJDG301&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These records cluster in their own segments rather than sitting beside the code they describe. A V7R4 SAVSYS yields about 34,000 of them.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PTF level&#039;&#039;&#039; field is the useful one: it distinguishes base modules from patched ones without a changelog, which is exactly what you need when a running machine and its install media disagree on addresses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; means &amp;quot;no PTF applied to this module&amp;quot; — &#039;&#039;&#039;not&#039;&#039;&#039; &amp;quot;identical to your install media&amp;quot;. Two machines can both report &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; and differ, because base levels themselves differ between RS releases. Compile and link dates make this checkable.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Calls between modules ==&lt;br /&gt;
External calls do not go through a table you can read off.&lt;br /&gt;
&lt;br /&gt;
A call is a two-instruction sequence — an ordinal loaded into &amp;lt;code&amp;gt;r11&amp;lt;/code&amp;gt;, then a &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into the &#039;&#039;&#039;BLA vector&#039;&#039;&#039; at the top of the address space. IBM&#039;s own term, from the Static Directory, is &#039;&#039;Pageable BLA&#039;&#039; for the pageable half.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V4R4   ori r11,r13,&amp;lt;ordinal&amp;gt; ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
V7R4   li  r11,&amp;lt;ordinal&amp;gt;     ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stub reached by the &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; computes the target arithmetically:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rldicr r11,r11,sh,59      ; ordinal x 4 (V4R4) or x 16 (V7R4)&lt;br /&gt;
addis  r11,r11,&amp;lt;simm&amp;gt;&lt;br /&gt;
mtctr  r11&lt;br /&gt;
bctr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so &amp;lt;code&amp;gt;callee = (sext16(simm) &amp;lt;&amp;lt; 16) + (ordinal &amp;lt;&amp;lt; sh)&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;simm&amp;lt;/code&amp;gt; values are not derivable and must be read from the vector — which is not carried in any container, so a dump is required once per build.&lt;br /&gt;
&lt;br /&gt;
The stub array is findable &#039;&#039;&#039;structurally&#039;&#039;&#039; — runs of 16-byte blocks with three constant words and one varying — which locates it without knowing the shift. Searching for a specific opcode pattern from another release will not find it.&lt;br /&gt;
&lt;br /&gt;
== Reading conditional branches ==&lt;br /&gt;
&lt;br /&gt;
Every policy decision in SLIC is a conditional branch, and getting one backwards silently inverts whatever it decides — the listing looks the same either way. The encoding is ordinary PowerPC, but two things about it are easy to get wrong when reading a listing rather than writing an assembler.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;code&amp;gt;BO&amp;lt;/code&amp;gt; selects the sense, &amp;lt;code&amp;gt;BI&amp;lt;/code&amp;gt; selects the bit.&#039;&#039;&#039; &amp;lt;code&amp;gt;BO = 12&amp;lt;/code&amp;gt; is branch-if-true and &amp;lt;code&amp;gt;BO = 4&amp;lt;/code&amp;gt; is branch-if-false. &amp;lt;code&amp;gt;BI&amp;lt;/code&amp;gt; numbers the condition register&#039;s bits end to end — &amp;lt;code&amp;gt;BI = 4 × field + bit&amp;lt;/code&amp;gt; — and the four bits of a field are, in order, &#039;&#039;&#039;LT, GT, EQ, SO&#039;&#039;&#039;. So within &amp;lt;code&amp;gt;CR0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;BI = 0&amp;lt;/code&amp;gt; is LT, &#039;&#039;&#039;&amp;lt;code&amp;gt;BI = 1&amp;lt;/code&amp;gt; is GT&#039;&#039;&#039; and &amp;lt;code&amp;gt;BI = 2&amp;lt;/code&amp;gt; is EQ; within &amp;lt;code&amp;gt;CR1&amp;lt;/code&amp;gt; the EQ bit is &amp;lt;code&amp;gt;BI = 6&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
That matters most after the idiom SLIC tests a policy bit with:&lt;br /&gt;
&lt;br /&gt;
 LWZ      4, 1148(16)     ; a flag byte out of an object&lt;br /&gt;
 RLDICL.  3, 4, 0, 63     ; r3 = byte &amp;amp;amp; 0x01, and set CR0&lt;br /&gt;
 BC       4, 1, ...       ; BO=4 branch-if-false, BI=1 GT&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;RLDICL.&amp;lt;/code&amp;gt; leaves 0 or 1 and sets &amp;lt;code&amp;gt;CR0&amp;lt;/code&amp;gt; by comparing it against zero, so GT is set exactly when the bit is on, and &#039;&#039;&#039;branch-if-not-GT is taken when the bit is CLEAR&#039;&#039;&#039;. Read &amp;lt;code&amp;gt;BI = 1&amp;lt;/code&amp;gt; as EQ instead and the same branch appears to be taken when the bit is &#039;&#039;&#039;set&#039;&#039;&#039; — the exact opposite, with nothing in the listing to show which reading is in force.&lt;br /&gt;
&lt;br /&gt;
A routine that uses two condition register fields settles the numbering without any external reference: a dispatch chain alternating &amp;lt;code&amp;gt;CMPI 0,…&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;BCLR 12,2&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;CMPI 1,…&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;BCLR 12,6&amp;lt;/code&amp;gt; is comparing a value against a series of constants and returning on each match, which is only a dispatch if &amp;lt;code&amp;gt;BI&amp;lt;/code&amp;gt; 2 and 6 are the EQ bits of &amp;lt;code&amp;gt;CR0&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CR1&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Two rendering traps make listings read backwards.&#039;&#039;&#039; Both apply to any disassembler that prints raw encoding fields instead of assembler syntax:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The destination is not always the first operand.&#039;&#039;&#039; &amp;lt;code&amp;gt;ADDI&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ADD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SUBF&amp;lt;/code&amp;gt; print it first; the logical forms &amp;lt;code&amp;gt;ORI&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;AND&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ANDC&amp;lt;/code&amp;gt; print &amp;lt;code&amp;gt;rS&amp;lt;/code&amp;gt; first and the destination &amp;lt;code&amp;gt;rA&amp;lt;/code&amp;gt; &#039;&#039;&#039;second&#039;&#039;&#039;. A load/modify/store triple is the giveaway: &amp;lt;code&amp;gt;LBZ 27,28(28)&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;ORI 27,26,1&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;STB 26,28(28)&amp;lt;/code&amp;gt; only makes sense as &amp;quot;load into r27, or in 1 giving r26, store r26&amp;quot;. Read left to right, whole routines look like a run of dead stores.&lt;br /&gt;
* &#039;&#039;&#039;The &amp;lt;code&amp;gt;Rc&amp;lt;/code&amp;gt; dot can go missing.&#039;&#039;&#039; &amp;lt;code&amp;gt;rlwinm.&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rlwimi.&amp;lt;/code&amp;gt; do set &amp;lt;code&amp;gt;CR0&amp;lt;/code&amp;gt;, but a decoder that appends the dot only for primary opcode 31 prints them without it — and then the branch after them looks like it is testing a condition register nothing wrote. Check bit 31 of the raw word before concluding a test is stale.&lt;br /&gt;
&lt;br /&gt;
== Traps worth knowing ==&lt;br /&gt;
* &#039;&#039;&#039;Never resolve a live pointer against a container image.&#039;&#039;&#039; A pointer read from a running machine names a runtime address; dereferencing it in a saved image lands on unrelated data and produces a plausible, wrong answer.&lt;br /&gt;
* &#039;&#039;&#039;Verify cross-image mappings by content, at the address you intend to use.&#039;&#039;&#039; A delta confirmed at one address does not hold across a segment.&lt;br /&gt;
* &#039;&#039;&#039;A positional coincidence looks exactly like a structural fact.&#039;&#039;&#039; Runs of plausible-looking pointers, matching offsets and familiar constants all occur by chance in images this size. Confirm with bytes.&lt;br /&gt;
* &#039;&#039;&#039;TOC contents are filled in at IPL.&#039;&#039;&#039; Container images hold unrelocated placeholders, so a TOC walk is only meaningful against live storage.&lt;br /&gt;
* &#039;&#039;&#039;Decode &amp;lt;code&amp;gt;BO&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;BI&amp;lt;/code&amp;gt; from the raw word before believing a branch, and record the sense you decoded.&#039;&#039;&#039; A branch that decides a policy bit is worth the thirty seconds; getting it wrong produces working-looking code that does the opposite of what the machine does, and the mistake survives review because the reasoning around it was written to match. See [[#Reading conditional branches]].&lt;br /&gt;
* &#039;&#039;&#039;A field the machine rebuilds at startup is an output, not an input.&#039;&#039;&#039; Configuration areas on disk are often regenerated from the machine&#039;s live configuration during power-on, and the code that later reads one may also stamp it on the way past. Reading such a field back as though it decided something is the same tautology as a model agreeing with its only caller, moved from code into data — and it is unusually convincing, because the value really is there and really is self-consistent. Establish who last wrote a field before deciding what it means.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEMCD]]&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC]]&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1785</id>
		<title>Reverse engineering SLIC</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1785"/>
		<updated>2026-08-09T13:29:48Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Remove the instruction-decoding section (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Reverse engineering &#039;&#039;&#039;SLIC&#039;&#039;&#039; — the Licensed Internal Code below the Machine Interface — is mostly a problem of turning addresses into names and getting bytes off the machine. This article collects the techniques that work, in the order you would actually use them, and the traps that cost the most time.&lt;br /&gt;
&lt;br /&gt;
It assumes access to a machine&#039;s DST or SST service tools, and installation media or a SAVSYS for offline work.&lt;br /&gt;
&lt;br /&gt;
== Start with the machine&#039;s own link map ==&lt;br /&gt;
Before writing any tooling, get the &#039;&#039;&#039;SLIC link map&#039;&#039;&#039; from the machine. It is reached through Display/Alter/Dump and can be printed to a spooled file, then exported.&lt;br /&gt;
&lt;br /&gt;
The printed format is one row per module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NICKNAME    ADDRESS(10+6)   PART NAME    VERSION RELEASE  REL DATE/TIME  INST DATE/TIME&lt;br /&gt;
###FLITE    FFFFFFFFF4 C29820   SRVC_MACRO_FLIGHTLOG   0007 0400 20190217 094024 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A V7R4 machine yields around 21,000 distinct modules. This single artefact answers &amp;quot;what is at this address&amp;quot; and &amp;quot;where is this module&amp;quot; authoritatively, for that machine, and it is the first thing to obtain.&lt;br /&gt;
&lt;br /&gt;
Two properties make it more useful than it first appears:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The spacing between consecutive entries equals the module&#039;s text length.&#039;&#039;&#039; Verified against the lengths &#039;&#039;Find LIC Module&#039;&#039; reports — exact matches. So the map gives extents as well as bases, which means any address can be resolved to a module &#039;&#039;and&#039;&#039; an offset within it.&lt;br /&gt;
* &#039;&#039;&#039;Module names are stable across PTFs; addresses are not.&#039;&#039;&#039; Look modules up by name whenever possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Part names are upper-cased in the printout but the &#039;&#039;Find LIC Module by name&#039;&#039; panel is &#039;&#039;&#039;case-sensitive&#039;&#039;&#039;. &amp;lt;code&amp;gt;IoHriTaggedVpd&amp;lt;/code&amp;gt; resolves; &amp;lt;code&amp;gt;IOHRITAGGEDVPD&amp;lt;/code&amp;gt; does not. Take the spelling from the on-screen display, not the print.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Getting bytes off the machine ==&lt;br /&gt;
Display/Alter/Dump can print a storage range to a spooled file. Exported as PDF and run through &amp;lt;code&amp;gt;pdftotext -layout&amp;lt;/code&amp;gt;, each line is an address and 32 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   FFFFFFFFC5 943160     3C40CC4DFBC1FFF0 FBE1FFF87C0802A6   F8010028F821FF01  3C000010F8010008&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The formatter &#039;&#039;&#039;collapses repeated lines&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        127 LINES    FFFFFFFF84 11B020   TO   FFFFFFFF84 11BFE0   SAME AS ABOVE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A naive parser silently sees a fraction of the data — in one case 44&amp;amp;thinsp;% of a 1&amp;amp;thinsp;MiB region — and reports no error. Any parser must expand these runs.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dumping a whole module at once is usually better than dumping the function you think you want: module extents are known from the link map, and the surrounding code frequently answers the next question.&lt;br /&gt;
&lt;br /&gt;
== Addresses ==&lt;br /&gt;
An SLS address is a &#039;&#039;&#039;40-bit segment identifier and a 24-bit offset&#039;&#039;&#039;, which is exactly how the &#039;&#039;Specify Address&#039;&#039; panel splits it, so segments are 16&amp;amp;thinsp;MiB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probe before dumping.&#039;&#039;&#039; Entering an address in an unmapped segment returns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
80 exception, segment does not exist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a free existence oracle. But probe the &#039;&#039;&#039;address you actually care about&#039;&#039;&#039;, not offset zero of its segment — segments are sparsely populated, and offset 0 being unmapped says nothing about the rest. A segment can be mapped at &amp;lt;code&amp;gt;0x010000&amp;lt;/code&amp;gt; and raise the exception at &amp;lt;code&amp;gt;0x120000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For a mapped address, the &#039;&#039;&#039;ADDRESSINFO&#039;&#039;&#039; Advanced Analysis command reports the page-directory entry and hardware page-table entries, confirming backing and page size.&lt;br /&gt;
&lt;br /&gt;
=== Runtime and staged addresses differ ===&lt;br /&gt;
The same module may appear at one address in the link map and another as its runtime text. Where these differ, &#039;&#039;&#039;module-relative offsets are stable&#039;&#039;&#039;: a symbol at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the staged image is at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the runtime image. Deriving runtime addresses this way works reliably; assuming a constant delta between two images does not.&lt;br /&gt;
&lt;br /&gt;
== Names from the code ==&lt;br /&gt;
Two structures let a container image be turned into a link map offline.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Traceback trailers.&#039;&#039;&#039; Every compilation unit ends with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; eyecatcher (&amp;lt;code&amp;gt;E3C2E3C2&amp;lt;/code&amp;gt;) followed by a pointer to a descriptor. A trailer covers a whole compilation unit, so it localises rather than pinpoints — and a forward scan for &amp;quot;the next trailer&amp;quot; will silently attribute a &#039;&#039;later&#039;&#039; function&#039;s name if the target has no trailer of its own.&lt;br /&gt;
* &#039;&#039;&#039;Link-loader descriptors.&#039;&#039;&#039; Richer: one per procedure, with the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Names beginning &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ mangled symbols.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Two mistakes here are expensive. First, &#039;&#039;&#039;do not require the entry address to fall inside a segment the container carries&#039;&#039;&#039; — runtime-only segments exist, and filtering on containment silently drops every module in them. Second, the name is not always at a fixed offset from the descriptor; scanning for the longest identifier run within the descriptor is more robust than assuming one.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module metadata ==&lt;br /&gt;
&#039;&#039;Find LIC Module&#039;&#039; reports, for any address: module name, nickname, compile and link/load timestamps, version and release level, &#039;&#039;&#039;PTF level&#039;&#039;&#039;, and the text, data and BSS extents plus the TOC address.&lt;br /&gt;
&lt;br /&gt;
The same record exists on media, anchored by the EBCDIC PTF-level string (&amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; for an unpatched module):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+0x00  PTF level     7 bytes    &amp;quot;SYSBASE&amp;quot;&lt;br /&gt;
+0x07  version       4 bytes    &amp;quot;0007&amp;quot; = V7&lt;br /&gt;
+0x0B  release/mod   4 bytes    &amp;quot;0400&amp;quot; = R4M0&lt;br /&gt;
+0x0F  nickname      8 bytes&lt;br /&gt;
+0x27  build id      7 bytes    &amp;quot;AJDG301&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These records cluster in their own segments rather than sitting beside the code they describe. A V7R4 SAVSYS yields about 34,000 of them.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PTF level&#039;&#039;&#039; field is the useful one: it distinguishes base modules from patched ones without a changelog, which is exactly what you need when a running machine and its install media disagree on addresses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; means &amp;quot;no PTF applied to this module&amp;quot; — &#039;&#039;&#039;not&#039;&#039;&#039; &amp;quot;identical to your install media&amp;quot;. Two machines can both report &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; and differ, because base levels themselves differ between RS releases. Compile and link dates make this checkable.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Calls between modules ==&lt;br /&gt;
External calls do not go through a table you can read off.&lt;br /&gt;
&lt;br /&gt;
A call is a two-instruction sequence — an ordinal loaded into &amp;lt;code&amp;gt;r11&amp;lt;/code&amp;gt;, then a &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into the &#039;&#039;&#039;BLA vector&#039;&#039;&#039; at the top of the address space. IBM&#039;s own term, from the Static Directory, is &#039;&#039;Pageable BLA&#039;&#039; for the pageable half.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V4R4   ori r11,r13,&amp;lt;ordinal&amp;gt; ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
V7R4   li  r11,&amp;lt;ordinal&amp;gt;     ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stub reached by the &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; computes the target arithmetically:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rldicr r11,r11,sh,59      ; ordinal x 4 (V4R4) or x 16 (V7R4)&lt;br /&gt;
addis  r11,r11,&amp;lt;simm&amp;gt;&lt;br /&gt;
mtctr  r11&lt;br /&gt;
bctr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so &amp;lt;code&amp;gt;callee = (sext16(simm) &amp;lt;&amp;lt; 16) + (ordinal &amp;lt;&amp;lt; sh)&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;simm&amp;lt;/code&amp;gt; values are not derivable and must be read from the vector — which is not carried in any container, so a dump is required once per build.&lt;br /&gt;
&lt;br /&gt;
The stub array is findable &#039;&#039;&#039;structurally&#039;&#039;&#039; — runs of 16-byte blocks with three constant words and one varying — which locates it without knowing the shift. Searching for a specific opcode pattern from another release will not find it.&lt;br /&gt;
&lt;br /&gt;
== Traps worth knowing ==&lt;br /&gt;
* &#039;&#039;&#039;Never resolve a live pointer against a container image.&#039;&#039;&#039; A pointer read from a running machine names a runtime address; dereferencing it in a saved image lands on unrelated data and produces a plausible, wrong answer.&lt;br /&gt;
* &#039;&#039;&#039;Verify cross-image mappings by content, at the address you intend to use.&#039;&#039;&#039; A delta confirmed at one address does not hold across a segment.&lt;br /&gt;
* &#039;&#039;&#039;A positional coincidence looks exactly like a structural fact.&#039;&#039;&#039; Runs of plausible-looking pointers, matching offsets and familiar constants all occur by chance in images this size. Confirm with bytes.&lt;br /&gt;
* &#039;&#039;&#039;TOC contents are filled in at IPL.&#039;&#039;&#039; Container images hold unrelocated placeholders, so a TOC walk is only meaningful against live storage.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEMCD]]&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC]]&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1784</id>
		<title>Reverse engineering SLIC</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1784"/>
		<updated>2026-08-09T13:27:03Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Add &amp;quot;Reading the instructions&amp;quot;: PowerPC AS instruction set, why stock disassemblers fail silently, the patched tools, and the opcode map (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Reverse engineering &#039;&#039;&#039;SLIC&#039;&#039;&#039; — the Licensed Internal Code below the Machine Interface — is mostly a problem of turning addresses into names and getting bytes off the machine. This article collects the techniques that work, in the order you would actually use them, and the traps that cost the most time.&lt;br /&gt;
&lt;br /&gt;
It assumes access to a machine&#039;s DST or SST service tools, and installation media or a SAVSYS for offline work.&lt;br /&gt;
&lt;br /&gt;
== Start with the machine&#039;s own link map ==&lt;br /&gt;
Before writing any tooling, get the &#039;&#039;&#039;SLIC link map&#039;&#039;&#039; from the machine. It is reached through Display/Alter/Dump and can be printed to a spooled file, then exported.&lt;br /&gt;
&lt;br /&gt;
The printed format is one row per module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NICKNAME    ADDRESS(10+6)   PART NAME    VERSION RELEASE  REL DATE/TIME  INST DATE/TIME&lt;br /&gt;
###FLITE    FFFFFFFFF4 C29820   SRVC_MACRO_FLIGHTLOG   0007 0400 20190217 094024 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A V7R4 machine yields around 21,000 distinct modules. This single artefact answers &amp;quot;what is at this address&amp;quot; and &amp;quot;where is this module&amp;quot; authoritatively, for that machine, and it is the first thing to obtain.&lt;br /&gt;
&lt;br /&gt;
Two properties make it more useful than it first appears:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The spacing between consecutive entries equals the module&#039;s text length.&#039;&#039;&#039; Verified against the lengths &#039;&#039;Find LIC Module&#039;&#039; reports — exact matches. So the map gives extents as well as bases, which means any address can be resolved to a module &#039;&#039;and&#039;&#039; an offset within it.&lt;br /&gt;
* &#039;&#039;&#039;Module names are stable across PTFs; addresses are not.&#039;&#039;&#039; Look modules up by name whenever possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Part names are upper-cased in the printout but the &#039;&#039;Find LIC Module by name&#039;&#039; panel is &#039;&#039;&#039;case-sensitive&#039;&#039;&#039;. &amp;lt;code&amp;gt;IoHriTaggedVpd&amp;lt;/code&amp;gt; resolves; &amp;lt;code&amp;gt;IOHRITAGGEDVPD&amp;lt;/code&amp;gt; does not. Take the spelling from the on-screen display, not the print.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Getting bytes off the machine ==&lt;br /&gt;
Display/Alter/Dump can print a storage range to a spooled file. Exported as PDF and run through &amp;lt;code&amp;gt;pdftotext -layout&amp;lt;/code&amp;gt;, each line is an address and 32 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   FFFFFFFFC5 943160     3C40CC4DFBC1FFF0 FBE1FFF87C0802A6   F8010028F821FF01  3C000010F8010008&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The formatter &#039;&#039;&#039;collapses repeated lines&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        127 LINES    FFFFFFFF84 11B020   TO   FFFFFFFF84 11BFE0   SAME AS ABOVE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A naive parser silently sees a fraction of the data — in one case 44&amp;amp;thinsp;% of a 1&amp;amp;thinsp;MiB region — and reports no error. Any parser must expand these runs.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dumping a whole module at once is usually better than dumping the function you think you want: module extents are known from the link map, and the surrounding code frequently answers the next question.&lt;br /&gt;
&lt;br /&gt;
== Addresses ==&lt;br /&gt;
An SLS address is a &#039;&#039;&#039;40-bit segment identifier and a 24-bit offset&#039;&#039;&#039;, which is exactly how the &#039;&#039;Specify Address&#039;&#039; panel splits it, so segments are 16&amp;amp;thinsp;MiB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probe before dumping.&#039;&#039;&#039; Entering an address in an unmapped segment returns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
80 exception, segment does not exist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a free existence oracle. But probe the &#039;&#039;&#039;address you actually care about&#039;&#039;&#039;, not offset zero of its segment — segments are sparsely populated, and offset 0 being unmapped says nothing about the rest. A segment can be mapped at &amp;lt;code&amp;gt;0x010000&amp;lt;/code&amp;gt; and raise the exception at &amp;lt;code&amp;gt;0x120000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For a mapped address, the &#039;&#039;&#039;ADDRESSINFO&#039;&#039;&#039; Advanced Analysis command reports the page-directory entry and hardware page-table entries, confirming backing and page size.&lt;br /&gt;
&lt;br /&gt;
=== Runtime and staged addresses differ ===&lt;br /&gt;
The same module may appear at one address in the link map and another as its runtime text. Where these differ, &#039;&#039;&#039;module-relative offsets are stable&#039;&#039;&#039;: a symbol at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the staged image is at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the runtime image. Deriving runtime addresses this way works reliably; assuming a constant delta between two images does not.&lt;br /&gt;
&lt;br /&gt;
== Names from the code ==&lt;br /&gt;
Two structures let a container image be turned into a link map offline.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Traceback trailers.&#039;&#039;&#039; Every compilation unit ends with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; eyecatcher (&amp;lt;code&amp;gt;E3C2E3C2&amp;lt;/code&amp;gt;) followed by a pointer to a descriptor. A trailer covers a whole compilation unit, so it localises rather than pinpoints — and a forward scan for &amp;quot;the next trailer&amp;quot; will silently attribute a &#039;&#039;later&#039;&#039; function&#039;s name if the target has no trailer of its own.&lt;br /&gt;
* &#039;&#039;&#039;Link-loader descriptors.&#039;&#039;&#039; Richer: one per procedure, with the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Names beginning &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ mangled symbols.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Two mistakes here are expensive. First, &#039;&#039;&#039;do not require the entry address to fall inside a segment the container carries&#039;&#039;&#039; — runtime-only segments exist, and filtering on containment silently drops every module in them. Second, the name is not always at a fixed offset from the descriptor; scanning for the longest identifier run within the descriptor is more robust than assuming one.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module metadata ==&lt;br /&gt;
&#039;&#039;Find LIC Module&#039;&#039; reports, for any address: module name, nickname, compile and link/load timestamps, version and release level, &#039;&#039;&#039;PTF level&#039;&#039;&#039;, and the text, data and BSS extents plus the TOC address.&lt;br /&gt;
&lt;br /&gt;
The same record exists on media, anchored by the EBCDIC PTF-level string (&amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; for an unpatched module):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+0x00  PTF level     7 bytes    &amp;quot;SYSBASE&amp;quot;&lt;br /&gt;
+0x07  version       4 bytes    &amp;quot;0007&amp;quot; = V7&lt;br /&gt;
+0x0B  release/mod   4 bytes    &amp;quot;0400&amp;quot; = R4M0&lt;br /&gt;
+0x0F  nickname      8 bytes&lt;br /&gt;
+0x27  build id      7 bytes    &amp;quot;AJDG301&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These records cluster in their own segments rather than sitting beside the code they describe. A V7R4 SAVSYS yields about 34,000 of them.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PTF level&#039;&#039;&#039; field is the useful one: it distinguishes base modules from patched ones without a changelog, which is exactly what you need when a running machine and its install media disagree on addresses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; means &amp;quot;no PTF applied to this module&amp;quot; — &#039;&#039;&#039;not&#039;&#039;&#039; &amp;quot;identical to your install media&amp;quot;. Two machines can both report &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; and differ, because base levels themselves differ between RS releases. Compile and link dates make this checkable.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Calls between modules ==&lt;br /&gt;
External calls do not go through a table you can read off.&lt;br /&gt;
&lt;br /&gt;
A call is a two-instruction sequence — an ordinal loaded into &amp;lt;code&amp;gt;r11&amp;lt;/code&amp;gt;, then a &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into the &#039;&#039;&#039;BLA vector&#039;&#039;&#039; at the top of the address space. IBM&#039;s own term, from the Static Directory, is &#039;&#039;Pageable BLA&#039;&#039; for the pageable half.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V4R4   ori r11,r13,&amp;lt;ordinal&amp;gt; ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
V7R4   li  r11,&amp;lt;ordinal&amp;gt;     ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stub reached by the &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; computes the target arithmetically:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rldicr r11,r11,sh,59      ; ordinal x 4 (V4R4) or x 16 (V7R4)&lt;br /&gt;
addis  r11,r11,&amp;lt;simm&amp;gt;&lt;br /&gt;
mtctr  r11&lt;br /&gt;
bctr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so &amp;lt;code&amp;gt;callee = (sext16(simm) &amp;lt;&amp;lt; 16) + (ordinal &amp;lt;&amp;lt; sh)&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;simm&amp;lt;/code&amp;gt; values are not derivable and must be read from the vector — which is not carried in any container, so a dump is required once per build.&lt;br /&gt;
&lt;br /&gt;
The stub array is findable &#039;&#039;&#039;structurally&#039;&#039;&#039; — runs of 16-byte blocks with three constant words and one varying — which locates it without knowing the shift. Searching for a specific opcode pattern from another release will not find it.&lt;br /&gt;
&lt;br /&gt;
== Reading the instructions ==&lt;br /&gt;
SLIC is compiled for &#039;&#039;&#039;PowerPC AS&#039;&#039;&#039;, IBM&#039;s variant of the architecture. It is the open PowerPC ISA plus a set of tagged-pointer and 16-byte-atomic instructions, and &#039;&#039;&#039;no stock disassembler knows them&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! group !! mnemonics&lt;br /&gt;
|-&lt;br /&gt;
| 16-byte load/store || &amp;lt;code&amp;gt;stmd&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;lmd&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;lq&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;stq&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| tagged (space-descriptor) load/store || &amp;lt;code&amp;gt;lsdi&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;lsdx&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;stsdi&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;stsdx&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| tag and XER-tag manipulation || &amp;lt;code&amp;gt;settag&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;txer&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;cmpla&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;mcrxrt&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;ltptr&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;dsixes&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| conditional select || &amp;lt;code&amp;gt;selii&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;selir&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;selri&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;selrr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| supervisor call || &amp;lt;code&amp;gt;scv&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
These are common — around 16&amp;amp;thinsp;% of words in a typical object — and they appear early, so the failure is not a scattering of question marks.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; &#039;&#039;&#039;This fails silently, and it does not look like a decoding problem.&#039;&#039;&#039; In one sample object the first &amp;lt;code&amp;gt;stq&amp;lt;/code&amp;gt; sits four bytes after a &amp;lt;code&amp;gt;settag&amp;lt;/code&amp;gt;. The tool decodes the &amp;lt;code&amp;gt;settag&amp;lt;/code&amp;gt;, cannot decode its fall-through, and ends the function there — reporting a clean 235-instruction function for a 9332-instruction program, with no error and no warning. The symptom presents as &amp;quot;the program is tiny&amp;quot;. Any instruction count from a stock PowerPC disassembler on IBM i code is meaningless.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Two tools have been extended to cover this set:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ghidra&#039;&#039;&#039; with a &amp;lt;code&amp;gt;powerpcas.sinc&amp;lt;/code&amp;gt; processor extension. This is the tool for &#039;&#039;reading&#039;&#039; code, because it decompiles. It still lacks &amp;lt;code&amp;gt;stq&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lq&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;scv&amp;lt;/code&amp;gt;, which is exactly the gap described above.&lt;br /&gt;
* &#039;&#039;&#039;capstone&#039;&#039;&#039;, in the fork at &amp;lt;code&amp;gt;github.com/cyberdotgent/capstone&amp;lt;/code&amp;gt;, branch &amp;lt;code&amp;gt;powerpc-as-support&amp;lt;/code&amp;gt;. A pre-pass decoder covering all of the above, tried ahead of the generated tables so nothing that already decoded changes. Use it for sweeps, statistics and scripted scans.&lt;br /&gt;
&lt;br /&gt;
Two build details cost time: the CMake option is &amp;lt;code&amp;gt;CAPSTONE_PPC_SUPPORT&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;CAPSTONE_POWERPC_SUPPORT&amp;lt;/code&amp;gt; — the wrong name builds cleanly and then fails at runtime with &amp;lt;code&amp;gt;CS_ERR_ARCH&amp;lt;/code&amp;gt; — and the mode is &amp;lt;code&amp;gt;ppc64be&amp;lt;/code&amp;gt;, since plain &amp;lt;code&amp;gt;ppc64&amp;lt;/code&amp;gt; is little-endian and decodes every word as garbage rather than erroring.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; &amp;lt;code&amp;gt;cstool&amp;lt;/code&amp;gt; &#039;&#039;&#039;stops at the first word it cannot decode&#039;&#039;&#039;. A batch sweep therefore silently reports only the prefix before the first AS instruction, which makes an unpatched tool look serviceable. Disassemble word-by-word, or resume past each stall.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The machine is the ground truth ===&lt;br /&gt;
Display/Alter/Dump of an MI program prints a &amp;lt;code&amp;gt;RISC INSTRUCTIONS&amp;lt;/code&amp;gt; listing produced by SLIC itself, which knows the whole instruction set. When an offline tool disagrees with that listing, the tool is wrong. Two disagreements are &#039;&#039;&#039;not&#039;&#039;&#039; faults:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Absolute branch targets.&#039;&#039;&#039; The machine prints the raw encoded field, offline tools sign-extend it: &amp;lt;code&amp;gt;4B800C43&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;BLA 0X3800C40&amp;lt;/code&amp;gt; on the machine and &amp;lt;code&amp;gt;bla 0xffffffffff800c40&amp;lt;/code&amp;gt; offline. The offline tools are right about the effective address — PowerPC sign-extends the &amp;lt;code&amp;gt;AA=1&amp;lt;/code&amp;gt; displacement, which is precisely why the BLA vector lives at the top of the address space.&lt;br /&gt;
* &#039;&#039;&#039;Extended mnemonics.&#039;&#039;&#039; The machine prints raw forms where offline tools print the extended one: &amp;lt;code&amp;gt;ADDI 12,0,25&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;li r12,0x19&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;BCCTR 20,0,0&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;bctr&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ORI 0,0,0&amp;lt;/code&amp;gt; vs &amp;lt;code&amp;gt;nop&amp;lt;/code&amp;gt;. Any automated comparison must normalise these or drown in false positives.&lt;br /&gt;
&lt;br /&gt;
The opcode map, taken from the machine&#039;s own listing:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! mnemonic !! primary !! XO&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SELII&amp;lt;/code&amp;gt; || 30 || 12&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SELIR&amp;lt;/code&amp;gt; || 30 || 13 / 461&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SELRI&amp;lt;/code&amp;gt; || 30 || 14 / 590&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SELRR&amp;lt;/code&amp;gt; || 30 || 15 / 463&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CMPLA&amp;lt;/code&amp;gt; || 31 || 64&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SETTAG&amp;lt;/code&amp;gt; || 31 || 499&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MCRXRT&amp;lt;/code&amp;gt; || 31 || 544&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TXER&amp;lt;/code&amp;gt; || 31 || 612&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LQ&amp;lt;/code&amp;gt; || 56 || 1, 2&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;LMD&amp;lt;/code&amp;gt; || 58 || 3&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;STQ&amp;lt;/code&amp;gt; || 62 || 2&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;STMD&amp;lt;/code&amp;gt; || 62 || 3&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SCV&amp;lt;/code&amp;gt; || 17 || bit 30 clear, bit 31 set&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SEL*&amp;lt;/code&amp;gt; family occupies primary 30, with the low XO bits selecting whether each of the two sources is a register or an immediate and the fourth operand naming an XER bit. Primary 56 is shared with the stock Power ISA &amp;lt;code&amp;gt;lq&amp;lt;/code&amp;gt;, so an AS decoder must gate on the low two bits being non-zero or it will break ordinary code; note also that the machine&#039;s &amp;lt;code&amp;gt;LQ&amp;lt;/code&amp;gt; takes a &#039;&#039;&#039;third operand&#039;&#039;&#039; (&amp;lt;code&amp;gt;LQ rt,d(ra),n&amp;lt;/code&amp;gt;) and so is not simply Power ISA 2.07 &amp;lt;code&amp;gt;lq&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Traps worth knowing ==&lt;br /&gt;
* &#039;&#039;&#039;Never resolve a live pointer against a container image.&#039;&#039;&#039; A pointer read from a running machine names a runtime address; dereferencing it in a saved image lands on unrelated data and produces a plausible, wrong answer.&lt;br /&gt;
* &#039;&#039;&#039;Verify cross-image mappings by content, at the address you intend to use.&#039;&#039;&#039; A delta confirmed at one address does not hold across a segment.&lt;br /&gt;
* &#039;&#039;&#039;A positional coincidence looks exactly like a structural fact.&#039;&#039;&#039; Runs of plausible-looking pointers, matching offsets and familiar constants all occur by chance in images this size. Confirm with bytes.&lt;br /&gt;
* &#039;&#039;&#039;TOC contents are filled in at IPL.&#039;&#039;&#039; Container images hold unrelocated placeholders, so a TOC walk is only meaningful against live storage.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEMCD]]&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC]]&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1783</id>
		<title>Reverse engineering SLIC</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Reverse_engineering_SLIC&amp;diff=1783"/>
		<updated>2026-08-09T13:06:12Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Practical techniques for SLIC reverse engineering: link map, dumps, addressing, names, calls&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Reverse engineering &#039;&#039;&#039;SLIC&#039;&#039;&#039; — the Licensed Internal Code below the Machine Interface — is mostly a problem of turning addresses into names and getting bytes off the machine. This article collects the techniques that work, in the order you would actually use them, and the traps that cost the most time.&lt;br /&gt;
&lt;br /&gt;
It assumes access to a machine&#039;s DST or SST service tools, and installation media or a SAVSYS for offline work.&lt;br /&gt;
&lt;br /&gt;
== Start with the machine&#039;s own link map ==&lt;br /&gt;
Before writing any tooling, get the &#039;&#039;&#039;SLIC link map&#039;&#039;&#039; from the machine. It is reached through Display/Alter/Dump and can be printed to a spooled file, then exported.&lt;br /&gt;
&lt;br /&gt;
The printed format is one row per module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
NICKNAME    ADDRESS(10+6)   PART NAME    VERSION RELEASE  REL DATE/TIME  INST DATE/TIME&lt;br /&gt;
###FLITE    FFFFFFFFF4 C29820   SRVC_MACRO_FLIGHTLOG   0007 0400 20190217 094024 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A V7R4 machine yields around 21,000 distinct modules. This single artefact answers &amp;quot;what is at this address&amp;quot; and &amp;quot;where is this module&amp;quot; authoritatively, for that machine, and it is the first thing to obtain.&lt;br /&gt;
&lt;br /&gt;
Two properties make it more useful than it first appears:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;The spacing between consecutive entries equals the module&#039;s text length.&#039;&#039;&#039; Verified against the lengths &#039;&#039;Find LIC Module&#039;&#039; reports — exact matches. So the map gives extents as well as bases, which means any address can be resolved to a module &#039;&#039;and&#039;&#039; an offset within it.&lt;br /&gt;
* &#039;&#039;&#039;Module names are stable across PTFs; addresses are not.&#039;&#039;&#039; Look modules up by name whenever possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Part names are upper-cased in the printout but the &#039;&#039;Find LIC Module by name&#039;&#039; panel is &#039;&#039;&#039;case-sensitive&#039;&#039;&#039;. &amp;lt;code&amp;gt;IoHriTaggedVpd&amp;lt;/code&amp;gt; resolves; &amp;lt;code&amp;gt;IOHRITAGGEDVPD&amp;lt;/code&amp;gt; does not. Take the spelling from the on-screen display, not the print.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Getting bytes off the machine ==&lt;br /&gt;
Display/Alter/Dump can print a storage range to a spooled file. Exported as PDF and run through &amp;lt;code&amp;gt;pdftotext -layout&amp;lt;/code&amp;gt;, each line is an address and 32 bytes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   FFFFFFFFC5 943160     3C40CC4DFBC1FFF0 FBE1FFF87C0802A6   F8010028F821FF01  3C000010F8010008&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The formatter &#039;&#039;&#039;collapses repeated lines&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        127 LINES    FFFFFFFF84 11B020   TO   FFFFFFFF84 11BFE0   SAME AS ABOVE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A naive parser silently sees a fraction of the data — in one case 44&amp;amp;thinsp;% of a 1&amp;amp;thinsp;MiB region — and reports no error. Any parser must expand these runs.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dumping a whole module at once is usually better than dumping the function you think you want: module extents are known from the link map, and the surrounding code frequently answers the next question.&lt;br /&gt;
&lt;br /&gt;
== Addresses ==&lt;br /&gt;
An SLS address is a &#039;&#039;&#039;40-bit segment identifier and a 24-bit offset&#039;&#039;&#039;, which is exactly how the &#039;&#039;Specify Address&#039;&#039; panel splits it, so segments are 16&amp;amp;thinsp;MiB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Probe before dumping.&#039;&#039;&#039; Entering an address in an unmapped segment returns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
80 exception, segment does not exist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a free existence oracle. But probe the &#039;&#039;&#039;address you actually care about&#039;&#039;&#039;, not offset zero of its segment — segments are sparsely populated, and offset 0 being unmapped says nothing about the rest. A segment can be mapped at &amp;lt;code&amp;gt;0x010000&amp;lt;/code&amp;gt; and raise the exception at &amp;lt;code&amp;gt;0x120000&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For a mapped address, the &#039;&#039;&#039;ADDRESSINFO&#039;&#039;&#039; Advanced Analysis command reports the page-directory entry and hardware page-table entries, confirming backing and page size.&lt;br /&gt;
&lt;br /&gt;
=== Runtime and staged addresses differ ===&lt;br /&gt;
The same module may appear at one address in the link map and another as its runtime text. Where these differ, &#039;&#039;&#039;module-relative offsets are stable&#039;&#039;&#039;: a symbol at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the staged image is at &amp;lt;code&amp;gt;+0x26d0&amp;lt;/code&amp;gt; in the runtime image. Deriving runtime addresses this way works reliably; assuming a constant delta between two images does not.&lt;br /&gt;
&lt;br /&gt;
== Names from the code ==&lt;br /&gt;
Two structures let a container image be turned into a link map offline.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Traceback trailers.&#039;&#039;&#039; Every compilation unit ends with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; eyecatcher (&amp;lt;code&amp;gt;E3C2E3C2&amp;lt;/code&amp;gt;) followed by a pointer to a descriptor. A trailer covers a whole compilation unit, so it localises rather than pinpoints — and a forward scan for &amp;quot;the next trailer&amp;quot; will silently attribute a &#039;&#039;later&#039;&#039; function&#039;s name if the target has no trailer of its own.&lt;br /&gt;
* &#039;&#039;&#039;Link-loader descriptors.&#039;&#039;&#039; Richer: one per procedure, with the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Names beginning &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ mangled symbols.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Two mistakes here are expensive. First, &#039;&#039;&#039;do not require the entry address to fall inside a segment the container carries&#039;&#039;&#039; — runtime-only segments exist, and filtering on containment silently drops every module in them. Second, the name is not always at a fixed offset from the descriptor; scanning for the longest identifier run within the descriptor is more robust than assuming one.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Module metadata ==&lt;br /&gt;
&#039;&#039;Find LIC Module&#039;&#039; reports, for any address: module name, nickname, compile and link/load timestamps, version and release level, &#039;&#039;&#039;PTF level&#039;&#039;&#039;, and the text, data and BSS extents plus the TOC address.&lt;br /&gt;
&lt;br /&gt;
The same record exists on media, anchored by the EBCDIC PTF-level string (&amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; for an unpatched module):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+0x00  PTF level     7 bytes    &amp;quot;SYSBASE&amp;quot;&lt;br /&gt;
+0x07  version       4 bytes    &amp;quot;0007&amp;quot; = V7&lt;br /&gt;
+0x0B  release/mod   4 bytes    &amp;quot;0400&amp;quot; = R4M0&lt;br /&gt;
+0x0F  nickname      8 bytes&lt;br /&gt;
+0x27  build id      7 bytes    &amp;quot;AJDG301&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These records cluster in their own segments rather than sitting beside the code they describe. A V7R4 SAVSYS yields about 34,000 of them.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;PTF level&#039;&#039;&#039; field is the useful one: it distinguishes base modules from patched ones without a changelog, which is exactly what you need when a running machine and its install media disagree on addresses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; means &amp;quot;no PTF applied to this module&amp;quot; — &#039;&#039;&#039;not&#039;&#039;&#039; &amp;quot;identical to your install media&amp;quot;. Two machines can both report &amp;lt;code&amp;gt;SYSBASE&amp;lt;/code&amp;gt; and differ, because base levels themselves differ between RS releases. Compile and link dates make this checkable.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Calls between modules ==&lt;br /&gt;
External calls do not go through a table you can read off.&lt;br /&gt;
&lt;br /&gt;
A call is a two-instruction sequence — an ordinal loaded into &amp;lt;code&amp;gt;r11&amp;lt;/code&amp;gt;, then a &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into the &#039;&#039;&#039;BLA vector&#039;&#039;&#039; at the top of the address space. IBM&#039;s own term, from the Static Directory, is &#039;&#039;Pageable BLA&#039;&#039; for the pageable half.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V4R4   ori r11,r13,&amp;lt;ordinal&amp;gt; ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
V7R4   li  r11,&amp;lt;ordinal&amp;gt;     ; bla &amp;lt;vector&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stub reached by the &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; computes the target arithmetically:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
rldicr r11,r11,sh,59      ; ordinal x 4 (V4R4) or x 16 (V7R4)&lt;br /&gt;
addis  r11,r11,&amp;lt;simm&amp;gt;&lt;br /&gt;
mtctr  r11&lt;br /&gt;
bctr&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so &amp;lt;code&amp;gt;callee = (sext16(simm) &amp;lt;&amp;lt; 16) + (ordinal &amp;lt;&amp;lt; sh)&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;simm&amp;lt;/code&amp;gt; values are not derivable and must be read from the vector — which is not carried in any container, so a dump is required once per build.&lt;br /&gt;
&lt;br /&gt;
The stub array is findable &#039;&#039;&#039;structurally&#039;&#039;&#039; — runs of 16-byte blocks with three constant words and one varying — which locates it without knowing the shift. Searching for a specific opcode pattern from another release will not find it.&lt;br /&gt;
&lt;br /&gt;
== Traps worth knowing ==&lt;br /&gt;
* &#039;&#039;&#039;Never resolve a live pointer against a container image.&#039;&#039;&#039; A pointer read from a running machine names a runtime address; dereferencing it in a saved image lands on unrelated data and produces a plausible, wrong answer.&lt;br /&gt;
* &#039;&#039;&#039;Verify cross-image mappings by content, at the address you intend to use.&#039;&#039;&#039; A delta confirmed at one address does not hold across a segment.&lt;br /&gt;
* &#039;&#039;&#039;A positional coincidence looks exactly like a structural fact.&#039;&#039;&#039; Runs of plausible-looking pointers, matching offsets and familiar constants all occur by chance in images this size. Confirm with bytes.&lt;br /&gt;
* &#039;&#039;&#039;TOC contents are filled in at IPL.&#039;&#039;&#039; Container images hold unrelocated placeholders, so a TOC walk is only meaningful against live storage.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEMCD]]&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC]]&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=File_Formats:PGM&amp;diff=1782</id>
		<title>File Formats:PGM</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=File_Formats:PGM&amp;diff=1782"/>
		<updated>2026-08-09T11:54:41Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Document the MI *PGM object: segments, SLS pointers, header chain, and where the instruction stream lives (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A &#039;&#039;&#039;&amp;lt;code&amp;gt;*PGM&amp;lt;/code&amp;gt;&#039;&#039;&#039; is a Machine Interface &#039;&#039;program object&#039;&#039;. It is not a file with a text section and a symbol table. It is a set of single-level store &#039;&#039;&#039;segments&#039;&#039;&#039;, chained together by 8-byte SLS pointers, with the executable instructions embedded in the first segment among the metadata that describes them.&lt;br /&gt;
&lt;br /&gt;
This page describes enough of that structure to walk a program object offline — that is, without a console session and without printing a storage dump for every object of interest. The bytes can come from a [[File Formats:SAVF|save file]], which makes any distribution medium, PTF or backup a source of real program objects to examine.&lt;br /&gt;
&lt;br /&gt;
Everything below is big endian, and text fields are EBCDIC.&lt;br /&gt;
&lt;br /&gt;
== Addressing ==&lt;br /&gt;
Pointers are 8 bytes: a 40-bit segment identifier in the high bits and a 24-bit offset in the low bits, so a segment is 16&amp;amp;thinsp;MiB. This is the same split used throughout the machine, including by the DST &#039;&#039;Display/Alter storage&#039;&#039; panel and by the SLS address field of a [[Data Structures:LID|LID]] directory record.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
segment = pointer &amp;gt;&amp;gt; 24&lt;br /&gt;
offset  = pointer &amp;amp; 0xFFFFFF&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An all-zero pointer means the object has no data for that structure. That is precisely what the &amp;lt;code&amp;gt;###INFO: OBJECT DOES NOT CONTAIN DATA FOR THIS SECTION&amp;lt;/code&amp;gt; line in a Display/Alter/Dump printout is reporting.&lt;br /&gt;
&lt;br /&gt;
Some fields are not pointers but &#039;&#039;&#039;&amp;lt;code&amp;gt;SEGOFF&amp;lt;/code&amp;gt;&#039;&#039;&#039; pairs: a 4-byte segment &#039;&#039;index&#039;&#039;, counting from one into the object&#039;s own segment table, followed by a 4-byte offset. These appear where a genuine pointer would have to be relocated when the object moves.&lt;br /&gt;
&lt;br /&gt;
The segments of one program have unrelated segment identifiers. A decoder therefore needs the whole set: a single segment cannot resolve its own pointers.&lt;br /&gt;
&lt;br /&gt;
== Segments ==&lt;br /&gt;
A single-module bound program typically has four segments, distinguished by the type field in each segment&#039;s own header:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Type&lt;br /&gt;
!Role&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0001&amp;lt;/code&amp;gt;&lt;br /&gt;
|The program object proper: all headers, tables, and the instruction stream.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0022&amp;lt;/code&amp;gt;&lt;br /&gt;
|Module constants and the module string directory.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0018&amp;lt;/code&amp;gt;&lt;br /&gt;
|Static storage.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0028&amp;lt;/code&amp;gt;&lt;br /&gt;
|Trace-back and mapping data.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that a program&#039;s segment table records a segment &#039;&#039;use&#039;&#039; code, while each segment&#039;s own header records a &#039;&#039;type&#039;&#039;. They are different numberings and should not be conflated.&lt;br /&gt;
&lt;br /&gt;
=== Segment header ===&lt;br /&gt;
Every MI segment opens with a header, called &amp;lt;code&amp;gt;YYSGHDR&amp;lt;/code&amp;gt; in IBM&#039;s own dump formatting.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Segment type&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x02&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Size, in 512-byte units&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|New flags&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x05&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|Flags&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Address of the owning object&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Space address&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Object header ===&lt;br /&gt;
Immediately after it, at &amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt; of the first segment, sits the object header, &amp;lt;code&amp;gt;YYEPAHDR&amp;lt;/code&amp;gt;. Offsets below are relative to it.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x02&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|MI object type&lt;br /&gt;
|Together with the next byte, &amp;lt;code&amp;gt;0x0201&amp;lt;/code&amp;gt; for a program.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x03&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|MI object subtype&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;&lt;br /&gt;
|30&lt;br /&gt;
|Object name&lt;br /&gt;
|EBCDIC.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x24&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Space size&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Creation timestamp&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Owning user profile&lt;br /&gt;
|A pointer to the profile object.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x48&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Context&lt;br /&gt;
|That is, the library.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Object space&lt;br /&gt;
|&#039;&#039;&#039;The pointer to the program header.&#039;&#039;&#039; Everything else hangs off this.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x5A&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|ASP&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x60&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Last-modified timestamp&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The type and subtype pair uses the same code space as the item descriptors in a save file, so one table of MI type codes serves both.&lt;br /&gt;
&lt;br /&gt;
== The program header ==&lt;br /&gt;
Found through the object header&#039;s object-space pointer; in practice it sits at offset &amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt; of the first segment.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Program attributes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the version table&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the segment table&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the activation header&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the signature table&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x28&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the program string directory&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to activation group information&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x40&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Activation start&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x48&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Activation end&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|&#039;&#039;&#039;Activation and PEP end&#039;&#039;&#039; — the last byte of the code&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x58&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Flags&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x5C&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Program state&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x90&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|Program type&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x94&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Program entry procedure module number&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x9C&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Program entry procedure string ID&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xA0&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Minimum parameters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xA2&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Maximum parameters&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xD0&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the program header extension&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xD8&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the trace-back locator&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xE0&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the module table&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xE8&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to observability information&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xF0&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the maintenance header&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The header extension adds a pointer to the GLU code list, &amp;lt;code&amp;gt;SEGOFF&amp;lt;/code&amp;gt; pairs for the program history and the segment table extension, and a 16-byte hardware feature set at &amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Version table ===&lt;br /&gt;
Forty bytes of packed version-release-modification halfwords, where &amp;lt;code&amp;gt;0x0740&amp;lt;/code&amp;gt; reads as V7R4M0. Among them are the binder&#039;s internal and MI levels at &amp;lt;code&amp;gt;+0x02&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;, the &#039;&#039;&#039;target&#039;&#039;&#039; release at &amp;lt;code&amp;gt;+0x06&amp;lt;/code&amp;gt;, the &#039;&#039;&#039;created-on&#039;&#039;&#039; release at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;, the language release at &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;, the CCSID at &amp;lt;code&amp;gt;+0x1E&amp;lt;/code&amp;gt; and the low and high optimisation levels at &amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;+0x22&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The target and created-on values here are what decide whether an object will restore onto a given release, so they are worth reading before attempting a restore that might fail.&lt;br /&gt;
&lt;br /&gt;
=== Segment table ===&lt;br /&gt;
A header of allocated size, entry count and version, then the entries beginning at &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;. &#039;&#039;&#039;Entries are a fixed 48 bytes&#039;&#039;&#039;; the size field is the allocation, not header plus count times entry, so deriving the stride from it gives the wrong answer.&lt;br /&gt;
&lt;br /&gt;
Each entry holds the segment address at &amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;, a limbo address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;, a declared page count at &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;, and a one-byte &#039;&#039;segment use&#039;&#039; at &amp;lt;code&amp;gt;+0x12&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; static storage, &amp;lt;code&amp;gt;0x02&amp;lt;/code&amp;gt; the program object, &amp;lt;code&amp;gt;0x04&amp;lt;/code&amp;gt; constants, &amp;lt;code&amp;gt;0x06&amp;lt;/code&amp;gt; trace-back.&lt;br /&gt;
&lt;br /&gt;
A parallel &#039;&#039;segment table extension&#039;&#039;, reached by a &amp;lt;code&amp;gt;SEGOFF&amp;lt;/code&amp;gt; in the program header extension, records how much of each segment is actually used as opposed to allocated. Its entries begin at &amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt; and are 24 bytes, of which the first four are the byte count.&lt;br /&gt;
&lt;br /&gt;
=== Activation header ===&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|&#039;&#039;&#039;Program entry procedure entry point&#039;&#039;&#039; — the first instruction&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|PBV size&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the PBV relocation array&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the static PBV array&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|PBV relocation count&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x24&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Dependent service program count&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x28&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the dependent service program array&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x4C&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Constant frame count&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the constant frame definition array&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x58&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Pointer to the program export array&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x60&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Export count&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
For a bound program with no exports most of these are zero. For a service program they are the published interface, and the dependent service program array is the object&#039;s dependency list — which makes it possible to work out what a program binds to without a machine to run &amp;lt;code&amp;gt;DSPPGM&amp;lt;/code&amp;gt; on.&lt;br /&gt;
&lt;br /&gt;
=== Maintenance header ===&lt;br /&gt;
Holds the copyright list size and count and a &amp;lt;code&amp;gt;SEGOFF&amp;lt;/code&amp;gt; to the copyright text — a 4-byte length followed by EBCDIC — along with &amp;lt;code&amp;gt;SEGOFF&amp;lt;/code&amp;gt; pairs for the external object list, static activation and export information, the last non-observable segment and size, and the lowest and highest PBV identifiers.&lt;br /&gt;
&lt;br /&gt;
== Modules ==&lt;br /&gt;
The module table has the same shape as the segment table: header, then 48-byte entries from &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;, each giving a pointer to a module header, a module domain and a module subtype.&lt;br /&gt;
&lt;br /&gt;
A module header is a long run of pointers: to the program header it belongs to, the copyright table, the module version table, binding information, static information, the end-of-line table, observability information, the module string directory, the entry point table, the VLIC table, the procedure table, module constants, and the module header extension. It also carries the module type at &amp;lt;code&amp;gt;+0x01&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;0x01&amp;lt;/code&amp;gt; for OPM and &amp;lt;code&amp;gt;0x03&amp;lt;/code&amp;gt; for ILE — the module attributes at &amp;lt;code&amp;gt;+0xA8&amp;lt;/code&amp;gt;, and the program entry procedure&#039;s dictionary ID, string ID, procedure number and parameter counts from &amp;lt;code&amp;gt;+0xAC&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;+0xBC&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Two of its pointers characteristically leave the program segment: the module string directory and the module constants both live in the &amp;lt;code&amp;gt;0x0022&amp;lt;/code&amp;gt; segment. When hunting for literal data referenced by the code — message identifiers, format names, table constants — that is the segment to search, and these two pointers give its exact extent.&lt;br /&gt;
&lt;br /&gt;
=== Module version table ===&lt;br /&gt;
This is the most immediately informative structure in the whole object.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x02&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Language release&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x0A&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Instruction release&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Target release&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x0E&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Created-on release&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Optimisation level&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x14&amp;lt;/code&amp;gt;&lt;br /&gt;
|30&lt;br /&gt;
|Source module name&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x32&amp;lt;/code&amp;gt;&lt;br /&gt;
|30&lt;br /&gt;
|Source module qualifier&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|20&lt;br /&gt;
|Compiler name&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x64&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Earliest compiler release&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Read the compiler name before spending any time on a disassembly. A module reporting &amp;lt;code&amp;gt;MX CONVERTED&amp;lt;/code&amp;gt; was &#039;&#039;translated&#039;&#039; from an older object rather than compiled from source at this release, and the generated code will not resemble what a current compiler emits.&lt;br /&gt;
&lt;br /&gt;
== The instruction stream ==&lt;br /&gt;
The code is a single contiguous run inside the first segment, bounded by two fields already listed above:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
start = activation header, program entry procedure entry point&lt;br /&gt;
end   = program header, activation and PEP end        (inclusive)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is 64-bit big-endian &#039;&#039;&#039;PowerPC AS&#039;&#039;&#039;. A stock disassembler invoked as &amp;lt;code&amp;gt;objdump -D -b binary -m powerpc:common64 -EB&amp;lt;/code&amp;gt;, with the load address adjusted to the start offset, will produce a listing whose addresses line up with anything printed by Display/Alter/Dump.&lt;br /&gt;
&lt;br /&gt;
Two caveats apply, and both matter.&lt;br /&gt;
&lt;br /&gt;
PowerPC AS is not plain PowerPC. The tagged-pointer instructions and other AS-only operations have no encoding in a stock PowerPC disassembler and will appear as invalid, or worse, as an unrelated mnemonic that looks plausible. Treat such a listing as a starting point rather than as authority.&lt;br /&gt;
&lt;br /&gt;
The run is also not pure code. Trace-back tables and constants are interleaved with instructions, so a linear sweep will decode data as code somewhere. For an object that still has its observability information, the trace-back locator and the module tables provide the boundaries needed to separate the two; for an object whose observability has been removed, they do not, and the separation has to be inferred from the code itself.&lt;br /&gt;
&lt;br /&gt;
== Scope of this description ==&lt;br /&gt;
Field offsets were derived by lining a printed Display/Alter/Dump of a program object up against the same object&#039;s bytes extracted from a save file, and then checked by decoding the object independently and comparing every field against the printout. Structures that the dump prints but that were empty in the object used — the signature table, the export and import arrays, the service program tables and the secondary entry point table — are located by pointer but their contents are not described here; establishing those needs a service program to work from.&lt;br /&gt;
&lt;br /&gt;
Only &amp;lt;code&amp;gt;*PGM&amp;lt;/code&amp;gt; is covered. &amp;lt;code&amp;gt;*SRVPGM&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;*MODULE&amp;lt;/code&amp;gt; share much of this layout but have additional tables of their own.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[File Formats:SAVF]] — how to get a program object&#039;s bytes off a machine or out of a distribution medium&lt;br /&gt;
* [[Data Structures:LID]] — the same single-level store address split, in a different container&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=File_Formats:SAVF&amp;diff=1781</id>
		<title>File Formats:SAVF</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=File_Formats:SAVF&amp;diff=1781"/>
		<updated>2026-08-09T11:53:42Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Document the SAVF container: chunk layer and checksum, item descriptors, sections, SRDS catalogue (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A &#039;&#039;&#039;SAVF&#039;&#039;&#039; (&#039;&#039;save file&#039;&#039;) is the container OS/400 and IBM i write with &amp;lt;code&amp;gt;SAVOBJ&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;SAVLIB&amp;lt;/code&amp;gt;, and read back with &amp;lt;code&amp;gt;RSTOBJ&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;RSTLIB&amp;lt;/code&amp;gt;. It holds Machine Interface objects — programs, files, data areas, libraries — in the form they have on disk, together with a catalogue describing what was saved and from which machine.&lt;br /&gt;
&lt;br /&gt;
Understanding the format is useful well beyond restoring a save file on a machine. It is the only practical way to get at the bytes of an MI object &#039;&#039;offline&#039;&#039;: the same byte stream also appears inside optical images and tape images, so a distribution medium, a PTF, or a backup is an extractable archive of real MI objects. What can be done with one once it is extracted is described in [[File Formats:PGM]] for programs.&lt;br /&gt;
&lt;br /&gt;
Everything below is big endian, and every text field is EBCDIC.&lt;br /&gt;
&lt;br /&gt;
== Three layers ==&lt;br /&gt;
It helps to separate three things that are often run together:&lt;br /&gt;
&lt;br /&gt;
* the &#039;&#039;&#039;chunk&#039;&#039;&#039; layer, which wraps the save stream in 528-byte units with a checksum on each;&lt;br /&gt;
* the &#039;&#039;&#039;item&#039;&#039;&#039; layer, which is a chain of saved objects, each a 512-byte descriptor followed by that object&#039;s segments;&lt;br /&gt;
* the &#039;&#039;&#039;catalogue&#039;&#039;&#039;, a single special item per save that lists the library and its objects.&lt;br /&gt;
&lt;br /&gt;
Only the chunk layer is specific to a save file held in &amp;lt;code&amp;gt;QSYS&amp;lt;/code&amp;gt;. When the same save is carried on optical or tape media, the chunk wrapper is absent and the item chain sits in the medium directly. A reader that separates the layers handles all three media with one item parser.&lt;br /&gt;
&lt;br /&gt;
== The chunk layer ==&lt;br /&gt;
A save file is exactly &#039;&#039;chunk count&#039;&#039; × 528 bytes. Chunk &#039;&#039;n&#039;&#039;, counting from zero, begins at file offset &amp;lt;code&amp;gt;n × 528&amp;lt;/code&amp;gt; and consists of 512 bytes of save-stream data followed by a 16-byte checksum. The logical save stream is the concatenation of the data halves, so translating a stream offset to a file offset is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
file_offset = (stream_offset / 512) * 528 + (stream_offset % 512)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== File header ===&lt;br /&gt;
The first 512 bytes of the stream — which are also the data half of chunk 1 — describe the container.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|MI creation timestamp&lt;br /&gt;
|Also the seed for every chunk checksum.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Chunk count&lt;br /&gt;
|32-bit form.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Machine type and model&lt;br /&gt;
|EBCDIC, model first: &amp;lt;code&amp;gt;42A 8286&amp;lt;/code&amp;gt; is an 8286-42A.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Release level&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x34&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Header length&lt;br /&gt;
|The first item starts here. Zero means 512.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Chunk count&lt;br /&gt;
|64-bit form, used when the 32-bit field would overflow.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x40&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&lt;br /&gt;
|Global checksum backup&lt;br /&gt;
|See below.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A valid file satisfies &amp;lt;code&amp;gt;chunk count == file size / 528&amp;lt;/code&amp;gt;; anything else means truncation. Because the header is itself chunk 1, verifying its checksum is the cheapest reliable test of whether a file is a save file at all.&lt;br /&gt;
&lt;br /&gt;
=== The global checksum displaces real data ===&lt;br /&gt;
This is the trap worth knowing about before writing any extractor. The last 16 bytes of the &#039;&#039;logical&#039;&#039; stream, at &amp;lt;code&amp;gt;chunk count × 512 − 16&amp;lt;/code&amp;gt;, are overwritten with a whole-file checksum. The data bytes they replaced are preserved in the file header at &amp;lt;code&amp;gt;+0x40&amp;lt;/code&amp;gt;, and a reader must put them back. A reader that does not will silently corrupt the tail of the last object it extracts, in a way that no chunk checksum will catch, because the chunk checksums are computed over the overwritten bytes.&lt;br /&gt;
&lt;br /&gt;
=== The chunk checksum ===&lt;br /&gt;
Each chunk&#039;s 16-byte trailer is the chunk number, counting from one, as a 4-byte big-endian integer, followed by a 12-byte digest. The digest is two folding passes built from a single primitive:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
chkadd(a, b):          # b is exactly one byte longer than a&lt;br /&gt;
    b[1:] += a &amp;lt;&amp;lt; 1    # big-endian magnitudes, carry propagated&lt;br /&gt;
    b[0]  += carry + (the bit shifted out of the top of a)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first pass takes the chunk number followed by the 512 data bytes and cuts them into eight parts of 61, 62, 63, 64, 65, 66, 67 and 68 bytes, then folds them in ascending order: &amp;lt;code&amp;gt;chkadd&amp;lt;/code&amp;gt; of the 61-byte part into the 62-byte part, that into the 63-byte part, and so on. The second pass takes the resulting 68 bytes, cuts them into parts of 5, 6, 7, 8, 9, 10, 11 and 12 bytes, and folds them the same way, leaving 12 bytes. The first 8 of those are then XORed with the file header&#039;s MI timestamp.&lt;br /&gt;
&lt;br /&gt;
There is one non-obvious detail. In both passes the parts are &#039;&#039;filled&#039;&#039; from the input in the order 61, 62, 63, 64, 65, 66, &#039;&#039;&#039;68, 67&#039;&#039;&#039; — and 5, 6, 7, 8, 9, 10, &#039;&#039;&#039;12, 11&#039;&#039;&#039; — while being &#039;&#039;folded&#039;&#039; in ascending order. An implementation that fills them in plain ascending order produces a plausible-looking wrong answer.&lt;br /&gt;
&lt;br /&gt;
The construction is a checksum, not a cryptographic hash. It detects media damage. It is not a tamper seal, and it carries no secret beyond a timestamp printed in the same header.&lt;br /&gt;
&lt;br /&gt;
== The item layer ==&lt;br /&gt;
Items are chained: parse the descriptor at the header length, add the item&#039;s computed length, repeat, and stop when the next item would begin past &amp;lt;code&amp;gt;(chunk count − 1) × 512&amp;lt;/code&amp;gt;. Every descriptor begins with &amp;lt;code&amp;gt;FFFFFFFF&amp;lt;/code&amp;gt;, which makes resynchronising after damage feasible.&lt;br /&gt;
&lt;br /&gt;
=== Item descriptor ===&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF&amp;lt;/code&amp;gt;&lt;br /&gt;
|Eyecatcher.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;&lt;br /&gt;
|10&lt;br /&gt;
|Object name&lt;br /&gt;
|EBCDIC. Replaced by a file ID for integrated file system objects.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x0E&amp;lt;/code&amp;gt;&lt;br /&gt;
|20&lt;br /&gt;
|Member name&lt;br /&gt;
|Empty unless the object has members.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x22&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|MI object type&lt;br /&gt;
|The same code space used throughout the machine: &amp;lt;code&amp;gt;0x0201&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;*PGM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0401&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;*LIB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x1901&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;*FILE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x19DB&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt;*SRDS&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x24&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|Flags&lt;br /&gt;
|Bit &amp;lt;code&amp;gt;0x40&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;0x80&amp;lt;/code&amp;gt; means the item is an IFS object.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x25&amp;lt;/code&amp;gt;&lt;br /&gt;
|3&lt;br /&gt;
|Catalogue offset&lt;br /&gt;
|Where this object&#039;s entry sits inside the catalogue.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x44&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Header occupation&lt;br /&gt;
|Bytes of the descriptor page actually used.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x48&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Stored length&lt;br /&gt;
|In 512-byte units, minus one.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x54&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Release created for&lt;br /&gt;
|Governs the section-entry layout below.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x56&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Metadata length&lt;br /&gt;
|For a catalogue item, the size of the catalogue.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x64&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Section count&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xC0&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Save timestamp&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xCC&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Total length&lt;br /&gt;
|In 512-byte units.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xD4&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Data length&lt;br /&gt;
|In 512-byte units. Always the total length less 4096 bytes.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x100&amp;lt;/code&amp;gt;&lt;br /&gt;
|14 × 8&lt;br /&gt;
|Pointer array&lt;br /&gt;
|See below.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x170&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Packed length&lt;br /&gt;
|Stored as the length less 512.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The pointer array holds single-level store addresses, but only the low 24 bits matter: they are an offset into the item, biased by 4096, so &amp;lt;code&amp;gt;(pointer &amp;amp;amp; 0xFFFFFF) − 4096&amp;lt;/code&amp;gt; gives an offset within the descriptor page. Index 1 locates the section length table and index 8 the section type table.&lt;br /&gt;
&lt;br /&gt;
=== Sections ===&lt;br /&gt;
A saved MI object is a set of segments, and each segment is one &#039;&#039;section&#039;&#039; of the item. Sections start at the first 4096-byte boundary after the descriptor and run consecutively, which is why the data length is always the total length less one page.&lt;br /&gt;
&lt;br /&gt;
The length table has one entry per section. On any modern release — when the &#039;&#039;release created for&#039;&#039; field exceeds 32 — an entry is 16 bytes: capacity, length, and the segment&#039;s single-level store address. Older saves use a 10-byte entry with a shifted 6-byte address and no separate length.&lt;br /&gt;
&lt;br /&gt;
The type table has one 8-byte entry per section, of which the first halfword is the segment type. This is the &#039;&#039;&#039;same value as the first halfword of the segment&#039;s own segment header&#039;&#039;&#039;, which is a useful consistency check when extracting: the item&#039;s idea of what a section is must agree with the segment&#039;s own.&lt;br /&gt;
&lt;br /&gt;
=== Item length and compression ===&lt;br /&gt;
An uncompressed item occupies its stored length. A packed item records a non-zero packed length, and the writer then realigns the following item on the enclosing 512-byte boundary, so the step from one item to the next is&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if packed == 512:        step = stored&lt;br /&gt;
elif packed &amp;gt; stored:    step = packed&lt;br /&gt;
else:&lt;br /&gt;
    slack  = stored - packed&lt;br /&gt;
    within = item_offset % 512&lt;br /&gt;
    if within == 0:      step = stored&lt;br /&gt;
    elif within &amp;lt; slack: step = packed + slack - within&lt;br /&gt;
    else:                step = stored + 512 - within&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The compression method is identifiable from the first six bytes of the packed data, which are EBCDIC eyecatchers:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Bytes&lt;br /&gt;
!EBCDIC&lt;br /&gt;
!&amp;lt;code&amp;gt;DTACPR&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;D3C46DE3D9E2&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;LD_TRS&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;*MEDIUM&amp;lt;/code&amp;gt;, the TERSE algorithm&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;D3C46DD3E9F1&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;LD_LZ1&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;*HIGH&amp;lt;/code&amp;gt;, IBM&#039;s LZ1&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;D3C46DE9D3C2&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;LD_ZLB&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;*ZLIB&amp;lt;/code&amp;gt;; the deflate stream begins 12 bytes in&lt;br /&gt;
|-&lt;br /&gt;
|none&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;code&amp;gt;*LOW&amp;lt;/code&amp;gt;, an SNA-style run-length scheme, recognisable only by decoding it&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note that these are &#039;&#039;not&#039;&#039; the compression used for a compressed LID payload; see [[Data Structures:LID]], where all four of these were tried and rejected.&lt;br /&gt;
&lt;br /&gt;
== The catalogue ==&lt;br /&gt;
Every save writes one save/restore descriptor space item, MI type &amp;lt;code&amp;gt;0x19DB&amp;lt;/code&amp;gt;, named &amp;lt;code&amp;gt;QSRDSSPC.&#039;&#039;n&#039;&#039;&amp;lt;/code&amp;gt;, ahead of the objects it describes. Items named &amp;lt;code&amp;gt;QSR.ADDITIONAL_INFO.*&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;QSRDSSPC.EA&amp;amp;nbsp;SRD*&amp;lt;/code&amp;gt; are continuation blocks belonging to the preceding descriptor, not new saves.&lt;br /&gt;
&lt;br /&gt;
The catalogue itself is the &#039;&#039;&#039;last&#039;&#039;&#039; &#039;&#039;metadata length&#039;&#039; bytes of that item&#039;s data. Its first byte is the save command, and that selects the shape: a library save has the layout below, while a save of the integrated file system produces a different, tree-structured descriptor.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|Save command&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x01&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|Target release&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x02&amp;lt;/code&amp;gt;&lt;br /&gt;
|30&lt;br /&gt;
|Saved library name&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|Base object type, &amp;lt;code&amp;gt;0x0401&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x22&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Save timestamp&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x2A&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Object count&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x34&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|System serial number&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x3C&amp;lt;/code&amp;gt;&lt;br /&gt;
|2&lt;br /&gt;
|ASP number&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x3E&amp;lt;/code&amp;gt;&lt;br /&gt;
|10&lt;br /&gt;
|Create authority&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x4C&amp;lt;/code&amp;gt;&lt;br /&gt;
|1&lt;br /&gt;
|Save-while-active indicator&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|10&lt;br /&gt;
|ASP name, target release 66 and later only&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Object descriptors follow, at &amp;lt;code&amp;gt;+0x50&amp;lt;/code&amp;gt; or at &amp;lt;code&amp;gt;+0x70&amp;lt;/code&amp;gt; when the ASP name is present. Each is 151 bytes on target release 49 and later, and 87 bytes before that. The first fields are the object name at &amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt; for 30 bytes, the MI object type at &amp;lt;code&amp;gt;+0x1E&amp;lt;/code&amp;gt;, and the owning user profile at &amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt; for 10 bytes. The size is a 4-byte field at &amp;lt;code&amp;gt;+0x43&amp;lt;/code&amp;gt;, multiplied by a second 4-byte field at &amp;lt;code&amp;gt;+0x79&amp;lt;/code&amp;gt; when that is non-zero. The remainder of the descriptor holds offsets, into the same buffer, of chains of length-prefixed records carrying the object&#039;s text description, service description, usage information, work-unit references and user information.&lt;br /&gt;
&lt;br /&gt;
Worth noticing for its own sake: the catalogue records the &#039;&#039;&#039;serial number of the machine that produced the save&#039;&#039;&#039;. A save file is not anonymous.&lt;br /&gt;
&lt;br /&gt;
== Practical consequences ==&lt;br /&gt;
* Any MI object can be lifted out of a save file byte for byte, with its segments separated and their segment identifiers intact. That is what makes offline analysis of a program object possible without console access to a machine and without printing a storage dump.&lt;br /&gt;
* Verifying the chunk checksums is a genuine integrity check on an archived save file, and can be done without a machine.&lt;br /&gt;
* The item chain and the catalogue are independent descriptions of the same set of objects. Where they disagree, the file has been damaged or truncated.&lt;br /&gt;
* Because the chunk layer is only present for a save file held in &amp;lt;code&amp;gt;QSYS&amp;lt;/code&amp;gt;, a save carved out of an optical or tape image is parsed by the same code with the chunk translation switched off.&lt;br /&gt;
&lt;br /&gt;
== Scope of this description ==&lt;br /&gt;
The layout was mapped with reference to jSAVF, an independently developed third-party reader, and then verified field by field against a real V7R4 save file. Where an object in that file also had a printed Display/Alter/Dump available, the bytes extracted here matched the printout exactly. The chunk checksum was reimplemented from scratch and verifies every chunk of the test file.&lt;br /&gt;
&lt;br /&gt;
Not established: the meaning of the 4-byte field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; of the file header, the layout of the integrated file system catalogue, and the LZ1 and TERSE decompressors.&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.anerty.net/software/file/jSAVF/?lang=en jSAVF] — a maintained third-party reader for save files, and the starting point for the layout described here.&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEMCD&amp;diff=1780</id>
		<title>System Files:QFILEMCD</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEMCD&amp;diff=1780"/>
		<updated>2026-08-08T20:38:12Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Correct the header field at 0x26: it carries the system serial number, not a build id&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;&#039;&#039;&#039; is the larger of the two container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It is a backup of &#039;&#039;&#039;SLIC&#039;&#039;&#039; itself — the System Licensed Internal Code that sits below OS/400 — stored as a small number of very large memory segments. Its internal format is called &#039;&#039;&#039;&amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;&#039;&#039;&#039; after the eyecatcher at offset zero.&lt;br /&gt;
&lt;br /&gt;
Practically, this is the file to reach for if you want to read the machine&#039;s own code without touching a running system. Its segments are a byte-for-byte image of what the link loader maps into memory, so an address recovered from a crash, a trace or a [[SRC|system reference code]] can be looked up directly in a file on your workstation. The companion file [[System Files:QFILEIML]] carries the loadable IOP, adapter and service processor microcode instead.&lt;br /&gt;
&lt;br /&gt;
Both files are containers of [[Data Structures:LID|LIDs]], but at different granularities, and the relationship between them is described under &#039;&#039;Two directories, two granularities&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
The figures quoted here come from one V4R4 image of 472,846,336 bytes (451&amp;amp;thinsp;MiB). Treat structure as general and numbers as release-specific; the format is unchanged from V4R4 through V7R4, across install media and SAVSYS output alike.&lt;br /&gt;
&lt;br /&gt;
== Header ==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|Eyecatcher &amp;lt;code&amp;gt;COPYDIR&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC (&amp;lt;code&amp;gt;C3 D6 D7 E8 C4 C9 D9 40&amp;lt;/code&amp;gt;), a zero byte, then the two EBCDIC characters &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|32-bit total size of the payload area — see below. Confirmed on three independent samples&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x26&amp;lt;/code&amp;gt;&lt;br /&gt;
|Release level, then the &#039;&#039;&#039;system serial number&#039;&#039;&#039;, EBCDIC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|Licensed Internal Code banner, EBCDIC, in 48-character chunks&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;&lt;br /&gt;
|Start of the directory&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The string in a V4R4 image reads:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V4R4M044-C6295  2606071417&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and in a V7R4 one taken by SAVSYS from a running machine:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V7R4M021-7886W&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first field is the release and modification level. &#039;&#039;&#039;The five characters after the hyphen are the system serial number.&#039;&#039;&#039; That is not an inference: the owner of the V7R4 machine confirms its serial is &amp;lt;code&amp;gt;7886W&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
On &#039;&#039;&#039;installation media&#039;&#039;&#039; the same field carries a build or media tag instead — a V7R4 install ISO reads &amp;lt;code&amp;gt;V7R4M021-821BV&amp;lt;/code&amp;gt; — so what the field means depends on how the image was produced. Both forms are five characters, which makes them easy to confuse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; A LIC backup is therefore &#039;&#039;&#039;not anonymous&#039;&#039;&#039;: it records the serial number of the machine it came from. The serial is also one of the values the system password is keyed on (see [[CISC AS/400 LIC Tapes]]), so treat these files as identifying if you share them.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the V4R4 sample the ten digits after the serial parse naturally as a timestamp of the form &amp;lt;code&amp;gt;YYMMDDHHMM&amp;lt;/code&amp;gt;, making that backup 2026-06-07 14:17. That part &#039;&#039;&#039;is&#039;&#039;&#039; an inference from the shape of the field, and the V7R4 sample carries binary rather than digits in the same place, so the layout after the serial is not fixed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The header is &#039;&#039;&#039;not&#039;&#039;&#039; a fixed 192 (&amp;lt;code&amp;gt;0xC0&amp;lt;/code&amp;gt;) bytes, despite older format notes saying so. The IBM legal banner runs on well past that point, and in this V4R4 image the directory does not begin until &amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;. A parser should locate the directory by scanning for the first 64-byte-aligned block that has the shape of an entry, rather than seeking to a constant.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 32-bit field at &amp;lt;code&amp;gt;0x1C&amp;lt;/code&amp;gt; holds &amp;lt;code&amp;gt;0x1C2F0000&amp;lt;/code&amp;gt;, which is exactly the end of the last segment&#039;s data. It is a total-payload-size field and makes a good consistency check after parsing the directory: accumulate the entries and you should arrive at the same number.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory is a run of 64-byte entries beginning at &amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Flags. See the bit-numbering warning below&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|SLS address of the saved segment&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Segment attributes; the top 16 bits carry the useful value&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x28&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Offset to the segment data, &#039;&#039;&#039;absolute from the start of the file&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Segment length, in &#039;&#039;&#039;raw bytes&#039;&#039;&#039; — not blocks&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x34&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two details cause most of the trouble people have with this structure, and both were originally got wrong here:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Flags use IBM&#039;s MSB-first bit numbering.&#039;&#039;&#039; Older notes describe the field as &amp;lt;code&amp;gt;bbt 0:3&amp;lt;/code&amp;gt;, and a reader used to LSB-first numbering will look in the bottom nibble and find nothing. Bit 0 is the &#039;&#039;most&#039;&#039; significant bit, so the value lives in the &#039;&#039;&#039;top&#039;&#039;&#039; nibble of the 8-byte field. A normal entry reads &amp;lt;code&amp;gt;0x1000000000000000&amp;lt;/code&amp;gt;; the end-of-directory marker reads &amp;lt;code&amp;gt;0xF000000000000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;The data offset is absolute.&#039;&#039;&#039; It is measured from the start of the file, not from the end of the directory. Reading it as relative shifts every extracted segment by the size of the directory, which produces code that disassembles almost plausibly and is wrong everywhere.&lt;br /&gt;
&lt;br /&gt;
In this image the directory holds &#039;&#039;&#039;32 entries&#039;&#039;&#039;, with the terminator at &amp;lt;code&amp;gt;0x9C0&amp;lt;/code&amp;gt; and the directory ending at &amp;lt;code&amp;gt;0xA00&amp;lt;/code&amp;gt;. The first entry has a data offset of zero, which means the header and directory physically occupy the first &amp;lt;code&amp;gt;0xA00&amp;lt;/code&amp;gt; bytes of the first segment&#039;s stored image. This is expected rather than a bug, but a tool that extracts that segment will see the container&#039;s own header at the front of it.&lt;br /&gt;
&lt;br /&gt;
Segment lengths are consistently a whole number of 4&amp;amp;thinsp;KiB pages less than a power-of-two boundary: &amp;lt;code&amp;gt;0xFFF000&amp;lt;/code&amp;gt; is 16&amp;amp;thinsp;MiB minus one page, &amp;lt;code&amp;gt;0x7FF000&amp;lt;/code&amp;gt; is 8&amp;amp;thinsp;MiB minus one page, and so on.&lt;br /&gt;
&lt;br /&gt;
== Contents of a typical backup ==&lt;br /&gt;
The 32 segments of this image, with names from a community-maintained SLS address reference. Where the name column is blank, the segment&#039;s purpose has not been established.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!SLS address&lt;br /&gt;
!Length&lt;br /&gt;
!Name&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB3 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB5 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC3 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (2)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC4 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (3)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC5 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (4)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC6 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (5)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC7 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Mixed — component code and NLS text pools&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC8 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|Mixed — bignum/JVM code and NLS text pools&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFF1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader TOC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFF2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Service LID&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFF4 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Service LID (2)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFFE 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|15&amp;amp;thinsp;MiB&lt;br /&gt;
|Pageable BLA&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader Information&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader Information, Code, Data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD3 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader Information (2)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD4 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Mixed — JVM strings and DST debug symbol table&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF90 010000&amp;lt;/code&amp;gt;&lt;br /&gt;
|60&amp;amp;thinsp;KiB&lt;br /&gt;
|LID Directory&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF91 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC2 A-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF92 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC2 B-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF93 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC1 A-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF94 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC1 B-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF95 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF96 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF9A 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF9B 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFA1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID Manager&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFA2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF69 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|IDE&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
So a backup of this shape is the SLIC boot and loader nucleus: link loader code and data, the loader&#039;s table of contents, the LID subsystem&#039;s own bookkeeping, and both IPL sides of the two nucleus LIDs. It is not the whole of the machine&#039;s code.&lt;br /&gt;
&lt;br /&gt;
=== A and B sides ===&lt;br /&gt;
Several segments appear twice, distinguished as &#039;&#039;A-side&#039;&#039; and &#039;&#039;B-side&#039;&#039;. An AS/400 keeps two copies of its Licensed Internal Code so that an update can be applied to one while the other remains a fallback. A normal, unattended IPL runs the &#039;&#039;&#039;B side&#039;&#039;&#039;, so B is what a running machine is executing and B is what static analysis should be done against. Because the two sides are normally near-identical, a byte comparison against the A side is not evidence that A is the live one — the test only means something on a segment that actually differs between them.&lt;br /&gt;
&lt;br /&gt;
== Two directories, two granularities ==&lt;br /&gt;
A common source of confusion is that &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; appears to have two completely different directory formats. It does, and they nest:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;coarse&#039;&#039;&#039; level is &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;&#039;s own directory, documented above: 64-byte entries, one per 16&amp;amp;thinsp;MiB-class memory segment, 32 of them.&lt;br /&gt;
* The &#039;&#039;&#039;fine&#039;&#039;&#039; level is a catalogue of individual LIDs, thousands of entries, using the 32-byte record described at [[Data Structures:LID]].&lt;br /&gt;
&lt;br /&gt;
The fine level is not a second header in the file. It is simply &#039;&#039;&#039;the contents of one particular segment&#039;&#039;&#039; — the one named &#039;&#039;LID Directory&#039;&#039;, at &amp;lt;code&amp;gt;FFFFFFFF90 010000&amp;lt;/code&amp;gt;. Extract that segment and you find, after a preamble of about 1536 bytes, an EBCDIC &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt; eyecatcher, a version label, and then the records. In this image the label reads &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;, which is the same label carried by [[System Files:QFILEIML]] — a quick way to confirm that two files came off the same media.&lt;br /&gt;
&lt;br /&gt;
That is also why tools which dump this file emit two dissimilar-looking listings: a short table of large memory extents, and a long list of LIDs. They are two levels of one structure, not two formats.&lt;br /&gt;
&lt;br /&gt;
== Extracting a segment ==&lt;br /&gt;
The practical recipe, and the reason this file is worth knowing about:&lt;br /&gt;
&lt;br /&gt;
# Read the &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt; eyecatcher at offset 0 to confirm the format.&lt;br /&gt;
# Find the directory by scanning 64-byte-aligned offsets for the first entry-shaped block, rather than assuming &amp;lt;code&amp;gt;0xC0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Walk entries until the flags field has &amp;lt;code&amp;gt;0xF&amp;lt;/code&amp;gt; in its &#039;&#039;&#039;top&#039;&#039;&#039; nibble.&lt;br /&gt;
# For the segment you want, seek to the data offset &#039;&#039;&#039;as an absolute file offset&#039;&#039;&#039; and read &#039;&#039;length&#039;&#039; raw bytes.&lt;br /&gt;
# Load the result at its SLS address in a disassembler. The bytes are what the link loader maps, so addresses match.&lt;br /&gt;
&lt;br /&gt;
Step 5 is the payoff. A 64-bit address such as &amp;lt;code&amp;gt;FFFFFFFFC6 1F1690&amp;lt;/code&amp;gt; can be typed straight into the DST &#039;&#039;Display/Alter storage&#039;&#039; panel on a live machine of the same build, and the sixteen rows it displays will match the extracted file byte for byte. Static and live analysis share one address space, which means you can do the slow work offline and use the machine only for confirmation.&lt;br /&gt;
&lt;br /&gt;
Two caveats on addresses. They are per-&#039;&#039;&#039;build&#039;&#039;&#039;, not per-release, so comparisons are only meaningful between identical builds; the same class sits at a quite different address on a V5R4 machine. And the SLS address recorded in the directory is the address the segment was &#039;&#039;&#039;saved from&#039;&#039;&#039;, which is not always where it runs — the resident nucleus segment, for instance, is stored in the container under the SID of the B-side nucleus LID rather than its runtime SID.&lt;br /&gt;
&lt;br /&gt;
== Reading the code ==&lt;br /&gt;
Once a segment is loaded, two structures make it navigable, and both are worth knowing because they turn addresses into names:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Traceback trailers.&#039;&#039;&#039; Every compilation unit ends its code with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; trailer, and many carry the module&#039;s name. A trailer names a whole compilation unit rather than a single function, so a hit means &amp;quot;this address is inside module X&amp;quot;, not &amp;quot;this address is function X&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Link-loader descriptor blocks.&#039;&#039;&#039; Considerably richer: one block per procedure, carrying the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name in EBCDIC at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Names beginning with &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ mangled symbols.&lt;br /&gt;
&lt;br /&gt;
Merging both across every segment of this V4R4 image yields roughly 184,000 named records, which is enough to name a substantial fraction of any address you encounter. See [[SRC]] for how to use that to get from a reference code back to a module.&lt;br /&gt;
&lt;br /&gt;
Calls between modules do not go through a conventional dispatch table, which surprises people disassembling SLIC for the first time. An external call is a two-instruction sequence — &amp;lt;code&amp;gt;ori r11,r13,&#039;&#039;ordinal&#039;&#039;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into a transfer vector at the very top of the address space — and the 16-byte stub it lands on computes the target arithmetically. There is no table to read off; the ordinal &#039;&#039;is&#039;&#039; the callee&#039;s word offset within a window, and the stub supplies the window. The stub constants cannot be derived and must be read from a dump of the transfer vector.&lt;br /&gt;
&lt;br /&gt;
== The trailing page ==&lt;br /&gt;
The payload area ends at &amp;lt;code&amp;gt;0x1C2F0000&amp;lt;/code&amp;gt;, but the file is one 4&amp;amp;thinsp;KiB page longer than that. The final page is not padding: it holds 468 non-zero 8-byte records, which appear to be address-and-value pairs.&lt;br /&gt;
&lt;br /&gt;
They fall into two clear populations. The first 110 are in ascending address order with a value of 8, addressing the &#039;&#039;Link Loader — LIC Data&#039;&#039; segment among others. The remaining 256 are identical to each other: the same address &amp;lt;code&amp;gt;0xFE911220&amp;lt;/code&amp;gt;, in the &#039;&#039;Pageable BLA&#039;&#039; segment, paired with the value &amp;lt;code&amp;gt;0x48000002&amp;lt;/code&amp;gt; — which as PowerPC is a branch-absolute to zero, the shape of a deliberately poisoned entry.&lt;br /&gt;
&lt;br /&gt;
This has the flavour of a fixup or relocation list applied after the segments are restored, but that is a guess from shape alone. It is recorded here because it is real, reproducible and unexplained, and because a parser that assumes the file ends with the payload will silently ignore it.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The purpose of the trailing page.&lt;br /&gt;
* The header bytes other than the eyecatcher, size field, release string and banner.&lt;br /&gt;
* The meaning of the segment attribute field&#039;s top 16 bits, which take values &amp;lt;code&amp;gt;0x0001&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; and correlate loosely with segment size.&lt;br /&gt;
* Names for the nine segments left blank in the table above.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1778</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1778"/>
		<updated>2026-08-08T18:49:12Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Restore Module headers section lost to a section-index shift; reorder; fold in V7R2 second-sample findings&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
This description is based on two samples: a V4R4 image of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;, and a V7R2 one of 288.7&amp;amp;thinsp;MiB, label &amp;lt;code&amp;gt;v7r2m00000.0.00&amp;lt;/code&amp;gt;, taken from an installation ISO. Unless a figure is attributed to a release, it comes from the V4R4 sample; the section &#039;&#039;Across releases&#039;&#039; sets out what is format and what merely happened to be true of one image.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
The layout is &#039;&#039;&#039;not at fixed offsets&#039;&#039;&#039;. 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.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;, low 24 bits, is the offset to the Licensed Internal Code banner. The directory header sits at exactly &#039;&#039;&#039;twice&#039;&#039;&#039; that offset, its records &amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt; further on, and the build label at header &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Release&lt;br /&gt;
!&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
!Banner&lt;br /&gt;
!Directory header&lt;br /&gt;
!Records&lt;br /&gt;
!Build label&lt;br /&gt;
|-&lt;br /&gt;
|V4R4&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|V7R2&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1020&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v7r2m00000.0.00&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
So the general layout is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x008&amp;lt;/code&amp;gt;&lt;br /&gt;
|Low 24 bits: offset to the banner. The rest of the header is not understood&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&amp;amp;nbsp;+&amp;amp;nbsp;&amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of a V4R4 container are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and of a V7R2 one:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0800 0010 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The seven-digit numbers are LIC product identifiers, and the same ones appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; belong together.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; differs between the two samples (&amp;lt;code&amp;gt;00e00000&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;) and is not understood. Two samples are not enough to fit it.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Payloads begin at the next 512-byte block boundary after the directory terminator.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
An older formulation, &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner and a 1998 copyright, and its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
About 30 payloads carry an &amp;lt;code&amp;gt;AJS&amp;lt;/code&amp;gt; build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry &amp;lt;code&amp;gt;AJG&amp;lt;/code&amp;gt; identifiers and are I/O offload (MFIOP) code instead; several of those carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking, which is not something a service processor does. The two families are &#039;&#039;mostly&#039;&#039; disjoint but not perfectly: at least one payload contains both identifiers.&lt;br /&gt;
&lt;br /&gt;
==== Module headers ====&lt;br /&gt;
Each of these images is not a monolithic firmware blob but a collection of &#039;&#039;&#039;linkable modules&#039;&#039;&#039;, each introduced by a header with the EBCDIC eyecatcher &#039;&#039;&#039;&amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt;&#039;&#039;&#039; (&amp;lt;code&amp;gt;D7 C7 D7 D4&amp;lt;/code&amp;gt;) — 119 of them in a V4R4 container and 104 in a V7R2 one, decoding identically. The useful fields are:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; eyecatcher&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;&lt;br /&gt;
|A LID identifier — but see the caveat below&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x24&amp;lt;/code&amp;gt;&lt;br /&gt;
|EBCDIC version string, e.g. &amp;lt;code&amp;gt;0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|8-byte build identifier, e.g. &amp;lt;code&amp;gt;AJSFGVB3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x54&amp;lt;/code&amp;gt;&lt;br /&gt;
|8-byte name of the module this header &#039;&#039;&#039;defines&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x60&amp;lt;/code&amp;gt;&lt;br /&gt;
|Slot table, 4-byte values&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xC0&amp;lt;/code&amp;gt;&lt;br /&gt;
|Import table: 12-byte entries, each an 8-byte name and a 4-byte linkage slot, terminated by eight EBCDIC &amp;lt;code&amp;gt;F&amp;lt;/code&amp;gt; characters&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Strings such as &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP SPCI3&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SP WT&amp;lt;/code&amp;gt; are &#039;&#039;&#039;module names in a link table&#039;&#039;&#039;, 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.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Worked example, from the header at &amp;lt;code&amp;gt;+0x59C&amp;lt;/code&amp;gt; of LID &amp;lt;code&amp;gt;A07008C2&amp;lt;/code&amp;gt;: build &amp;lt;code&amp;gt;AJSFGVB3&amp;lt;/code&amp;gt;, defines &amp;lt;code&amp;gt;SP SB&amp;lt;/code&amp;gt;, and imports &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;SP SPCI5&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CUANSI&amp;lt;/code&amp;gt;, with the import table running to its terminator at &amp;lt;code&amp;gt;+0x1B4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Both families share a common utility layer, which is why their vocabulary overlaps: &amp;lt;code&amp;gt;CUANSI&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUCONV&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUIO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUMEMORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUMISC&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CUSTO&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;SRASCOMN&amp;lt;/code&amp;gt; for RAS common code.&lt;br /&gt;
&lt;br /&gt;
==== Reading the dependency graph ====&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; header is worth knowing about.&lt;br /&gt;
&lt;br /&gt;
Doing so reveals a clean pattern. The &#039;&#039;&#039;numbered&#039;&#039;&#039; names — &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SPCI5&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;MOPT9&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPD1&amp;lt;/code&amp;gt; — are imported by many modules and &#039;&#039;&#039;defined by none&#039;&#039;&#039;. The &#039;&#039;&#039;lettered&#039;&#039;&#039; members of the same families — &amp;lt;code&amp;gt;MOPTA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPD2&amp;lt;/code&amp;gt; — each import their immediate predecessor and are present as real modules.&lt;br /&gt;
&lt;br /&gt;
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 following section establishes by a completely independent route.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Caveat.&#039;&#039;&#039; The LID identifier at &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt; of a &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; 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 &#039;&#039;contents&#039;&#039; are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. Two independent lines of evidence agree on this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the instruction stream.&#039;&#039;&#039; All payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Across 4.1&amp;amp;thinsp;MB of service-processor code there is not one &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt;, and no payload has a vector table. Privileged operations are almost as scarce: six instructions of the &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt; family and four cache or TLB operations in the whole set.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state at all — only LR, CTR and XER are touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the link tables.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== The supervisor call interface ====&lt;br /&gt;
Since the supervisor itself is absent, the &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;r0&amp;lt;/code&amp;gt; and arguments from &amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Call&lt;br /&gt;
!Count&lt;br /&gt;
!Observed arguments&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;&lt;br /&gt;
|262&lt;br /&gt;
|—&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt;&lt;br /&gt;
|131&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x16&amp;lt;/code&amp;gt; in every instance&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x03A4&amp;lt;/code&amp;gt;&lt;br /&gt;
|106&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r4 = 5&amp;lt;/code&amp;gt;; unique to one module&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt; is one of exactly three values: &amp;lt;code&amp;gt;0x83010000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83020000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83030000&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first two are the interesting pair: &amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt; occurs exactly half as often as &amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;, and always on the same resource number, which is the signature of an acquire/release pair around a critical section. The &amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Beyond that the call numbers cannot be decoded, because the code that implements them is not on this medium.&lt;br /&gt;
&lt;br /&gt;
==== A caution about what this firmware does ====&lt;br /&gt;
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. &#039;&#039;&#039;No such claim is supported by this file.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; link names. A search for the entire relevant vocabulary — &amp;lt;code&amp;gt;POWER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FAN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;THERMAL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SPCN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;VPD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SECUR&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SERIAL&amp;lt;/code&amp;gt; and more, in both EBCDIC and ASCII, over every byte — returns nothing in any service-processor module. The same vocabulary &#039;&#039;is&#039;&#039; present elsewhere in the container, but only inside SLIC payloads.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
One bound on that negative: readable code averages about 46&amp;amp;thinsp;% of 1&amp;amp;thinsp;KiB blocks across these images, and one 119&amp;amp;thinsp;KiB payload is entirely opaque. The supported statement is that nothing is visible in the readable portion, not that nothing exists.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read the banner offset from &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and &#039;&#039;&#039;derive&#039;&#039;&#039; the directory position from it, rather than assuming a constant;&lt;br /&gt;
# read 32-byte records until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# place the payload area at the next block boundary after that terminator;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
Step 2 is the one that catches people. An implementation that hardcodes the V4R4 directory offset of &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; does not fail loudly on a V7R2 container — it reports zero records and a nonsensical payload start. Deriving the offsets costs nothing and works on both.&lt;br /&gt;
&lt;br /&gt;
== Across releases ==&lt;br /&gt;
Comparing a V4R4 image with a V7R2 one shows how much of this is format and how much was accident of a single sample.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&lt;br /&gt;
!V4R4&lt;br /&gt;
!V7R2&lt;br /&gt;
|-&lt;br /&gt;
|Records&lt;br /&gt;
|632&lt;br /&gt;
|961&lt;br /&gt;
|-&lt;br /&gt;
|Compressed&lt;br /&gt;
|341&lt;br /&gt;
|557&lt;br /&gt;
|-&lt;br /&gt;
|Payload&lt;br /&gt;
|77.5&amp;amp;thinsp;MiB&lt;br /&gt;
|288.7&amp;amp;thinsp;MiB&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; module headers&lt;br /&gt;
|119&lt;br /&gt;
|104&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The record format, the &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; module header and its field offsets, the payload tiling rule and the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator are all unchanged. What varies is the header offsets, which the header itself declares.&lt;br /&gt;
&lt;br /&gt;
The service processor module namespace is also strikingly stable. Fourteen &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; module names are defined in both releases, and the pattern of numbered names being imported but never defined — the evidence that they live in flash on the card — reproduces exactly sixteen years apart. So does the supervisor call vocabulary, with V7R2 adding one new call number.&lt;br /&gt;
&lt;br /&gt;
What did change is on the SLIC side, and it is what you would expect once the service processor and panel stop being discrete cards. The concrete hardware driver classes are simply gone in V7R2, while the message protocol and resource model that sat on top of them survive and grow. In their place, the panel and service processor objects are constructed from new &#039;&#039;virtual&#039;&#039; VPD providers. The interface is preserved and the implementation behind it is virtualised — which is why code written against the older message classes still reads as recognisable on a modern machine.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The header field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt;, which differs between samples (&amp;lt;code&amp;gt;00e00000&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The rest of the header between &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; and the banner.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why some payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* The &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; identifier discrepancy described above.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1777</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1777"/>
		<updated>2026-08-08T18:47:07Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Update tooling and open questions from the V7R2 sample; add release-comparison section (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
The layout is &#039;&#039;&#039;not at fixed offsets&#039;&#039;&#039;. 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.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;, low 24 bits, is the offset to the Licensed Internal Code banner. The directory header sits at exactly &#039;&#039;&#039;twice&#039;&#039;&#039; that offset, its records &amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt; further on, and the build label at header &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Release&lt;br /&gt;
!&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
!Banner&lt;br /&gt;
!Directory header&lt;br /&gt;
!Records&lt;br /&gt;
!Build label&lt;br /&gt;
|-&lt;br /&gt;
|V4R4&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|V7R2&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1020&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v7r2m00000.0.00&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
So the general layout is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x008&amp;lt;/code&amp;gt;&lt;br /&gt;
|Low 24 bits: offset to the banner. The rest of the header is not understood&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&amp;amp;nbsp;+&amp;amp;nbsp;&amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of a V4R4 container are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and of a V7R2 one:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0800 0010 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The seven-digit numbers are LIC product identifiers, and the same ones appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; belong together.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; differs between the two samples (&amp;lt;code&amp;gt;00e00000&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;) and is not understood. Two samples are not enough to fit it.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Payloads begin at the next 512-byte block boundary after the directory terminator.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
An older formulation, &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner and a 1998 copyright, and its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
About 30 payloads carry an &amp;lt;code&amp;gt;AJS&amp;lt;/code&amp;gt; build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry &amp;lt;code&amp;gt;AJG&amp;lt;/code&amp;gt; identifiers and are I/O offload (MFIOP) code instead; several of those carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking, which is not something a service processor does. The two families are &#039;&#039;mostly&#039;&#039; disjoint but not perfectly: at least one payload contains both identifiers.&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. Two independent lines of evidence agree on this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the instruction stream.&#039;&#039;&#039; All payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Across 4.1&amp;amp;thinsp;MB of service-processor code there is not one &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt;, and no payload has a vector table. Privileged operations are almost as scarce: six instructions of the &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt; family and four cache or TLB operations in the whole set.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state at all — only LR, CTR and XER are touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the link tables.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== The supervisor call interface ====&lt;br /&gt;
Since the supervisor itself is absent, the &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;r0&amp;lt;/code&amp;gt; and arguments from &amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Call&lt;br /&gt;
!Count&lt;br /&gt;
!Observed arguments&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;&lt;br /&gt;
|262&lt;br /&gt;
|—&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt;&lt;br /&gt;
|131&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x16&amp;lt;/code&amp;gt; in every instance&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x03A4&amp;lt;/code&amp;gt;&lt;br /&gt;
|106&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r4 = 5&amp;lt;/code&amp;gt;; unique to one module&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt; is one of exactly three values: &amp;lt;code&amp;gt;0x83010000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83020000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83030000&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first two are the interesting pair: &amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt; occurs exactly half as often as &amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;, and always on the same resource number, which is the signature of an acquire/release pair around a critical section. The &amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Beyond that the call numbers cannot be decoded, because the code that implements them is not on this medium.&lt;br /&gt;
&lt;br /&gt;
==== A caution about what this firmware does ====&lt;br /&gt;
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. &#039;&#039;&#039;No such claim is supported by this file.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; link names. A search for the entire relevant vocabulary — &amp;lt;code&amp;gt;POWER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FAN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;THERMAL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SPCN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;VPD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SECUR&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SERIAL&amp;lt;/code&amp;gt; and more, in both EBCDIC and ASCII, over every byte — returns nothing in any service-processor module. The same vocabulary &#039;&#039;is&#039;&#039; present elsewhere in the container, but only inside SLIC payloads.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
One bound on that negative: readable code averages about 46&amp;amp;thinsp;% of 1&amp;amp;thinsp;KiB blocks across these images, and one 119&amp;amp;thinsp;KiB payload is entirely opaque. The supported statement is that nothing is visible in the readable portion, not that nothing exists.&lt;br /&gt;
&lt;br /&gt;
==== Reading the dependency graph ====&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; header is worth knowing about.&lt;br /&gt;
&lt;br /&gt;
Doing so reveals a clean pattern. The &#039;&#039;&#039;numbered&#039;&#039;&#039; names — &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SPCI5&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;MOPT9&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPD1&amp;lt;/code&amp;gt; — are imported by many modules and &#039;&#039;&#039;defined by none&#039;&#039;&#039;. The &#039;&#039;&#039;lettered&#039;&#039;&#039; members of the same families — &amp;lt;code&amp;gt;MOPTA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPD2&amp;lt;/code&amp;gt; — each import their immediate predecessor and are present as real modules.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Caveat.&#039;&#039;&#039; The LID identifier at &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt; of a &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; 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 &#039;&#039;contents&#039;&#039; are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read the banner offset from &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and &#039;&#039;&#039;derive&#039;&#039;&#039; the directory position from it, rather than assuming a constant;&lt;br /&gt;
# read 32-byte records until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# place the payload area at the next block boundary after that terminator;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
Step 2 is the one that catches people. An implementation that hardcodes the V4R4 directory offset of &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; does not fail loudly on a V7R2 container — it reports zero records and a nonsensical payload start. Deriving the offsets costs nothing and works on both.&lt;br /&gt;
&lt;br /&gt;
== Across releases ==&lt;br /&gt;
Comparing a V4R4 image with a V7R2 one shows how much of this is format and how much was accident of a single sample.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!&lt;br /&gt;
!V4R4&lt;br /&gt;
!V7R2&lt;br /&gt;
|-&lt;br /&gt;
|Records&lt;br /&gt;
|632&lt;br /&gt;
|961&lt;br /&gt;
|-&lt;br /&gt;
|Compressed&lt;br /&gt;
|341&lt;br /&gt;
|557&lt;br /&gt;
|-&lt;br /&gt;
|Payload&lt;br /&gt;
|77.5&amp;amp;thinsp;MiB&lt;br /&gt;
|288.7&amp;amp;thinsp;MiB&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; module headers&lt;br /&gt;
|119&lt;br /&gt;
|104&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The record format, the &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; module header and its field offsets, the payload tiling rule and the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator are all unchanged. What varies is the header offsets, which the header itself declares.&lt;br /&gt;
&lt;br /&gt;
The service processor module namespace is also strikingly stable. Fourteen &amp;lt;code&amp;gt;SP&amp;lt;/code&amp;gt; module names are defined in both releases, and the pattern of numbered names being imported but never defined — the evidence that they live in flash on the card — reproduces exactly sixteen years apart. So does the supervisor call vocabulary, with V7R2 adding one new call number.&lt;br /&gt;
&lt;br /&gt;
What did change is on the SLIC side, and it is what you would expect once the service processor and panel stop being discrete cards. The concrete hardware driver classes are simply gone in V7R2, while the message protocol and resource model that sat on top of them survive and grow. In their place, the panel and service processor objects are constructed from new &#039;&#039;virtual&#039;&#039; VPD providers. The interface is preserved and the implementation behind it is virtualised — which is why code written against the older message classes still reads as recognisable on a modern machine.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The header field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt;, which differs between samples (&amp;lt;code&amp;gt;00e00000&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;).&lt;br /&gt;
* The rest of the header between &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; and the banner.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why some payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* The &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; identifier discrepancy described above.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read 32-byte records from &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# compute the payload start as &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, rather than trusting the offset field;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The meaning of the header bytes at &amp;lt;code&amp;gt;0x004&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x1FF&amp;lt;/code&amp;gt;, and of the four-byte preamble before &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1776</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1776"/>
		<updated>2026-08-08T18:46:48Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Replace the file-size payload-start rule with one derivable from the directory alone (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
The layout is &#039;&#039;&#039;not at fixed offsets&#039;&#039;&#039;. 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.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;, low 24 bits, is the offset to the Licensed Internal Code banner. The directory header sits at exactly &#039;&#039;&#039;twice&#039;&#039;&#039; that offset, its records &amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt; further on, and the build label at header &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Release&lt;br /&gt;
!&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
!Banner&lt;br /&gt;
!Directory header&lt;br /&gt;
!Records&lt;br /&gt;
!Build label&lt;br /&gt;
|-&lt;br /&gt;
|V4R4&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|V7R2&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1020&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v7r2m00000.0.00&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
So the general layout is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x008&amp;lt;/code&amp;gt;&lt;br /&gt;
|Low 24 bits: offset to the banner. The rest of the header is not understood&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&amp;amp;nbsp;+&amp;amp;nbsp;&amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of a V4R4 container are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and of a V7R2 one:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0800 0010 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The seven-digit numbers are LIC product identifiers, and the same ones appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; belong together.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; differs between the two samples (&amp;lt;code&amp;gt;00e00000&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;) and is not understood. Two samples are not enough to fit it.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Payloads begin at the next 512-byte block boundary after the directory terminator.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
An older formulation, &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, 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.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner and a 1998 copyright, and its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
About 30 payloads carry an &amp;lt;code&amp;gt;AJS&amp;lt;/code&amp;gt; build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry &amp;lt;code&amp;gt;AJG&amp;lt;/code&amp;gt; identifiers and are I/O offload (MFIOP) code instead; several of those carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking, which is not something a service processor does. The two families are &#039;&#039;mostly&#039;&#039; disjoint but not perfectly: at least one payload contains both identifiers.&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. Two independent lines of evidence agree on this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the instruction stream.&#039;&#039;&#039; All payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Across 4.1&amp;amp;thinsp;MB of service-processor code there is not one &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt;, and no payload has a vector table. Privileged operations are almost as scarce: six instructions of the &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt; family and four cache or TLB operations in the whole set.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state at all — only LR, CTR and XER are touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the link tables.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== The supervisor call interface ====&lt;br /&gt;
Since the supervisor itself is absent, the &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;r0&amp;lt;/code&amp;gt; and arguments from &amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Call&lt;br /&gt;
!Count&lt;br /&gt;
!Observed arguments&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;&lt;br /&gt;
|262&lt;br /&gt;
|—&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt;&lt;br /&gt;
|131&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x16&amp;lt;/code&amp;gt; in every instance&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x03A4&amp;lt;/code&amp;gt;&lt;br /&gt;
|106&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r4 = 5&amp;lt;/code&amp;gt;; unique to one module&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt; is one of exactly three values: &amp;lt;code&amp;gt;0x83010000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83020000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83030000&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first two are the interesting pair: &amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt; occurs exactly half as often as &amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;, and always on the same resource number, which is the signature of an acquire/release pair around a critical section. The &amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Beyond that the call numbers cannot be decoded, because the code that implements them is not on this medium.&lt;br /&gt;
&lt;br /&gt;
==== A caution about what this firmware does ====&lt;br /&gt;
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. &#039;&#039;&#039;No such claim is supported by this file.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; link names. A search for the entire relevant vocabulary — &amp;lt;code&amp;gt;POWER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FAN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;THERMAL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SPCN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;VPD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SECUR&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SERIAL&amp;lt;/code&amp;gt; and more, in both EBCDIC and ASCII, over every byte — returns nothing in any service-processor module. The same vocabulary &#039;&#039;is&#039;&#039; present elsewhere in the container, but only inside SLIC payloads.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
One bound on that negative: readable code averages about 46&amp;amp;thinsp;% of 1&amp;amp;thinsp;KiB blocks across these images, and one 119&amp;amp;thinsp;KiB payload is entirely opaque. The supported statement is that nothing is visible in the readable portion, not that nothing exists.&lt;br /&gt;
&lt;br /&gt;
==== Reading the dependency graph ====&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; header is worth knowing about.&lt;br /&gt;
&lt;br /&gt;
Doing so reveals a clean pattern. The &#039;&#039;&#039;numbered&#039;&#039;&#039; names — &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SPCI5&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;MOPT9&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPD1&amp;lt;/code&amp;gt; — are imported by many modules and &#039;&#039;&#039;defined by none&#039;&#039;&#039;. The &#039;&#039;&#039;lettered&#039;&#039;&#039; members of the same families — &amp;lt;code&amp;gt;MOPTA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPD2&amp;lt;/code&amp;gt; — each import their immediate predecessor and are present as real modules.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Caveat.&#039;&#039;&#039; The LID identifier at &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt; of a &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; 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 &#039;&#039;contents&#039;&#039; are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. All 632 payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Exactly one payload contains a single &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; in 289&amp;amp;thinsp;KiB, which is a data coincidence, and no payload has a vector table.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state anywhere: no &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt;, no segment or TLB or cache operations, and only LR, CTR and XER touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read 32-byte records from &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# compute the payload start as &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, rather than trusting the offset field;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The meaning of the header bytes at &amp;lt;code&amp;gt;0x004&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x1FF&amp;lt;/code&amp;gt;, and of the four-byte preamble before &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1775</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1775"/>
		<updated>2026-08-08T18:46:37Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Generalise the file layout from a second (V7R2) sample: the header carries its own offsets (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
The layout is &#039;&#039;&#039;not at fixed offsets&#039;&#039;&#039;. 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.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;, low 24 bits, is the offset to the Licensed Internal Code banner. The directory header sits at exactly &#039;&#039;&#039;twice&#039;&#039;&#039; that offset, its records &amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt; further on, and the build label at header &amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Release&lt;br /&gt;
!&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
!Banner&lt;br /&gt;
!Directory header&lt;br /&gt;
!Records&lt;br /&gt;
!Build label&lt;br /&gt;
|-&lt;br /&gt;
|V4R4&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|V7R2&lt;br /&gt;
|&amp;lt;code&amp;gt;ff000800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x800&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1000&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1020&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;v7r2m00000.0.00&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
So the general layout is:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x008&amp;lt;/code&amp;gt;&lt;br /&gt;
|Low 24 bits: offset to the banner. The rest of the header is not understood&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;banner&#039;&#039;&amp;amp;nbsp;×&amp;amp;nbsp;2&amp;amp;nbsp;+&amp;amp;nbsp;&amp;lt;code&amp;gt;0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of a V4R4 container are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and of a V7R2 one:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0800 0010 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The seven-digit numbers are LIC product identifiers, and the same ones appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. 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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; belong together.&lt;br /&gt;
&lt;br /&gt;
The field at &amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt; differs between the two samples (&amp;lt;code&amp;gt;00e00000&amp;lt;/code&amp;gt; against &amp;lt;code&amp;gt;00100000&amp;lt;/code&amp;gt;) and is not understood. Two samples are not enough to fit it.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; an offset into &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;, immediately past the directory terminator — and the payloads then tile to the final byte of the file with nothing left over.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner and a 1998 copyright, and its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
About 30 payloads carry an &amp;lt;code&amp;gt;AJS&amp;lt;/code&amp;gt; build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry &amp;lt;code&amp;gt;AJG&amp;lt;/code&amp;gt; identifiers and are I/O offload (MFIOP) code instead; several of those carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking, which is not something a service processor does. The two families are &#039;&#039;mostly&#039;&#039; disjoint but not perfectly: at least one payload contains both identifiers.&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. Two independent lines of evidence agree on this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the instruction stream.&#039;&#039;&#039; All payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Across 4.1&amp;amp;thinsp;MB of service-processor code there is not one &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt;, and no payload has a vector table. Privileged operations are almost as scarce: six instructions of the &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt; family and four cache or TLB operations in the whole set.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state at all — only LR, CTR and XER are touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the link tables.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== The supervisor call interface ====&lt;br /&gt;
Since the supervisor itself is absent, the &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;r0&amp;lt;/code&amp;gt; and arguments from &amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Call&lt;br /&gt;
!Count&lt;br /&gt;
!Observed arguments&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;&lt;br /&gt;
|262&lt;br /&gt;
|—&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt;&lt;br /&gt;
|131&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x16&amp;lt;/code&amp;gt; in every instance&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x03A4&amp;lt;/code&amp;gt;&lt;br /&gt;
|106&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r4 = 5&amp;lt;/code&amp;gt;; unique to one module&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt; is one of exactly three values: &amp;lt;code&amp;gt;0x83010000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83020000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83030000&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first two are the interesting pair: &amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt; occurs exactly half as often as &amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;, and always on the same resource number, which is the signature of an acquire/release pair around a critical section. The &amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Beyond that the call numbers cannot be decoded, because the code that implements them is not on this medium.&lt;br /&gt;
&lt;br /&gt;
==== A caution about what this firmware does ====&lt;br /&gt;
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. &#039;&#039;&#039;No such claim is supported by this file.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; link names. A search for the entire relevant vocabulary — &amp;lt;code&amp;gt;POWER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FAN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;THERMAL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SPCN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;VPD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SECUR&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SERIAL&amp;lt;/code&amp;gt; and more, in both EBCDIC and ASCII, over every byte — returns nothing in any service-processor module. The same vocabulary &#039;&#039;is&#039;&#039; present elsewhere in the container, but only inside SLIC payloads.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
One bound on that negative: readable code averages about 46&amp;amp;thinsp;% of 1&amp;amp;thinsp;KiB blocks across these images, and one 119&amp;amp;thinsp;KiB payload is entirely opaque. The supported statement is that nothing is visible in the readable portion, not that nothing exists.&lt;br /&gt;
&lt;br /&gt;
==== Reading the dependency graph ====&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; header is worth knowing about.&lt;br /&gt;
&lt;br /&gt;
Doing so reveals a clean pattern. The &#039;&#039;&#039;numbered&#039;&#039;&#039; names — &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SPCI5&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;MOPT9&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPD1&amp;lt;/code&amp;gt; — are imported by many modules and &#039;&#039;&#039;defined by none&#039;&#039;&#039;. The &#039;&#039;&#039;lettered&#039;&#039;&#039; members of the same families — &amp;lt;code&amp;gt;MOPTA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPD2&amp;lt;/code&amp;gt; — each import their immediate predecessor and are present as real modules.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Caveat.&#039;&#039;&#039; The LID identifier at &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt; of a &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; 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 &#039;&#039;contents&#039;&#039; are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. All 632 payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Exactly one payload contains a single &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; in 289&amp;amp;thinsp;KiB, which is a data coincidence, and no payload has a vector table.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state anywhere: no &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt;, no segment or TLB or cache operations, and only LR, CTR and XER touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read 32-byte records from &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# compute the payload start as &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, rather than trusting the offset field;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The meaning of the header bytes at &amp;lt;code&amp;gt;0x004&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x1FF&amp;lt;/code&amp;gt;, and of the four-byte preamble before &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1774</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1774"/>
		<updated>2026-08-08T17:37:59Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Strengthen the no-supervisor section with the independent link-table evidence (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC, followed by a short and largely unexplored header&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;&lt;br /&gt;
|Payload area&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of the file are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner at &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The three seven-digit numbers are LIC product identifiers, and the same three appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. The build label at &amp;lt;code&amp;gt;0x410&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;, likewise identical between the two files, which is a convenient way to confirm that a given &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; came off the same media.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; an offset into &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;, immediately past the directory terminator — and the payloads then tile to the final byte of the file with nothing left over.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner and a 1998 copyright, and its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
About 30 payloads carry an &amp;lt;code&amp;gt;AJS&amp;lt;/code&amp;gt; build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry &amp;lt;code&amp;gt;AJG&amp;lt;/code&amp;gt; identifiers and are I/O offload (MFIOP) code instead; several of those carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking, which is not something a service processor does. The two families are &#039;&#039;mostly&#039;&#039; disjoint but not perfectly: at least one payload contains both identifiers.&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. Two independent lines of evidence agree on this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the instruction stream.&#039;&#039;&#039; All payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Across 4.1&amp;amp;thinsp;MB of service-processor code there is not one &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt;, and no payload has a vector table. Privileged operations are almost as scarce: six instructions of the &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt; family and four cache or TLB operations in the whole set.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state at all — only LR, CTR and XER are touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;From the link tables.&#039;&#039;&#039; 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==== The supervisor call interface ====&lt;br /&gt;
Since the supervisor itself is absent, the &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; 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 &amp;lt;code&amp;gt;r0&amp;lt;/code&amp;gt; and arguments from &amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Call&lt;br /&gt;
!Count&lt;br /&gt;
!Observed arguments&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;&lt;br /&gt;
|262&lt;br /&gt;
|—&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt;&lt;br /&gt;
|131&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x16&amp;lt;/code&amp;gt; in every instance&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x03A4&amp;lt;/code&amp;gt;&lt;br /&gt;
|106&lt;br /&gt;
|&amp;lt;code&amp;gt;r3 = 0x64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;r4 = 5&amp;lt;/code&amp;gt;; unique to one module&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|&amp;lt;code&amp;gt;r3&amp;lt;/code&amp;gt; is one of exactly three values: &amp;lt;code&amp;gt;0x83010000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83020000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x83030000&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first two are the interesting pair: &amp;lt;code&amp;gt;0x0208&amp;lt;/code&amp;gt; occurs exactly half as often as &amp;lt;code&amp;gt;0x020C&amp;lt;/code&amp;gt;, and always on the same resource number, which is the signature of an acquire/release pair around a critical section. The &amp;lt;code&amp;gt;0x0358&amp;lt;/code&amp;gt; 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.&lt;br /&gt;
&lt;br /&gt;
Beyond that the call numbers cannot be decoded, because the code that implements them is not on this medium.&lt;br /&gt;
&lt;br /&gt;
==== A caution about what this firmware does ====&lt;br /&gt;
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. &#039;&#039;&#039;No such claim is supported by this file.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; link names. A search for the entire relevant vocabulary — &amp;lt;code&amp;gt;POWER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FAN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;THERMAL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SPCN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;VPD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PASSWORD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SECUR&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SERIAL&amp;lt;/code&amp;gt; and more, in both EBCDIC and ASCII, over every byte — returns nothing in any service-processor module. The same vocabulary &#039;&#039;is&#039;&#039; present elsewhere in the container, but only inside SLIC payloads.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
One bound on that negative: readable code averages about 46&amp;amp;thinsp;% of 1&amp;amp;thinsp;KiB blocks across these images, and one 119&amp;amp;thinsp;KiB payload is entirely opaque. The supported statement is that nothing is visible in the readable portion, not that nothing exists.&lt;br /&gt;
&lt;br /&gt;
==== Reading the dependency graph ====&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; header is worth knowing about.&lt;br /&gt;
&lt;br /&gt;
Doing so reveals a clean pattern. The &#039;&#039;&#039;numbered&#039;&#039;&#039; names — &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SPCI5&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;MOPT9&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPD1&amp;lt;/code&amp;gt; — are imported by many modules and &#039;&#039;&#039;defined by none&#039;&#039;&#039;. The &#039;&#039;&#039;lettered&#039;&#039;&#039; members of the same families — &amp;lt;code&amp;gt;MOPTA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPD2&amp;lt;/code&amp;gt; — each import their immediate predecessor and are present as real modules.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Caveat.&#039;&#039;&#039; The LID identifier at &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt; of a &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; 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 &#039;&#039;contents&#039;&#039; are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. All 632 payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Exactly one payload contains a single &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; in 289&amp;amp;thinsp;KiB, which is a data coincidence, and no payload has a vector table.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state anywhere: no &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt;, no segment or TLB or cache operations, and only LR, CTR and XER touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read 32-byte records from &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# compute the payload start as &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, rather than trusting the offset field;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The meaning of the header bytes at &amp;lt;code&amp;gt;0x004&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x1FF&amp;lt;/code&amp;gt;, and of the four-byte preamble before &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1773</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1773"/>
		<updated>2026-08-08T17:37:37Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: 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)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC, followed by a short and largely unexplored header&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;&lt;br /&gt;
|Payload area&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of the file are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner at &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The three seven-digit numbers are LIC product identifiers, and the same three appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. The build label at &amp;lt;code&amp;gt;0x410&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;, likewise identical between the two files, which is a convenient way to confirm that a given &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; came off the same media.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; an offset into &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;, immediately past the directory terminator — and the payloads then tile to the final byte of the file with nothing left over.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner and a 1998 copyright, and its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
About 30 payloads carry an &amp;lt;code&amp;gt;AJS&amp;lt;/code&amp;gt; build identifier and are service-processor code, ranging from a few tens of kilobytes to a few hundred. A further handful carry &amp;lt;code&amp;gt;AJG&amp;lt;/code&amp;gt; identifiers and are I/O offload (MFIOP) code instead; several of those carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking, which is not something a service processor does. The two families are &#039;&#039;mostly&#039;&#039; disjoint but not perfectly: at least one payload contains both identifiers.&lt;br /&gt;
&lt;br /&gt;
==== Module headers ====&lt;br /&gt;
Each of these images is not a monolithic firmware blob but a collection of &#039;&#039;&#039;linkable modules&#039;&#039;&#039;, each introduced by a header with the EBCDIC eyecatcher &#039;&#039;&#039;&amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt;&#039;&#039;&#039; (&amp;lt;code&amp;gt;D7 C7 D7 D4&amp;lt;/code&amp;gt;). There are 119 such headers in the container. The useful fields are:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|&amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; eyecatcher&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;&lt;br /&gt;
|A LID identifier — but see the caveat below&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x24&amp;lt;/code&amp;gt;&lt;br /&gt;
|EBCDIC version string, e.g. &amp;lt;code&amp;gt;0100&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|8-byte build identifier, e.g. &amp;lt;code&amp;gt;AJSFGVB3&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x54&amp;lt;/code&amp;gt;&lt;br /&gt;
|8-byte name of the module this header &#039;&#039;&#039;defines&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x60&amp;lt;/code&amp;gt;&lt;br /&gt;
|Slot table, 4-byte values&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0xC0&amp;lt;/code&amp;gt;&lt;br /&gt;
|Import table: 12-byte entries, each an 8-byte name and a 4-byte linkage slot, terminated by eight EBCDIC &amp;lt;code&amp;gt;F&amp;lt;/code&amp;gt; characters&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; Strings such as &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP SPCI3&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SP WT&amp;lt;/code&amp;gt; are &#039;&#039;&#039;module names in a link table&#039;&#039;&#039;, 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.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Worked example, from the header at &amp;lt;code&amp;gt;+0x59C&amp;lt;/code&amp;gt; of LID &amp;lt;code&amp;gt;A07008C2&amp;lt;/code&amp;gt;: build &amp;lt;code&amp;gt;AJSFGVB3&amp;lt;/code&amp;gt;, defines &amp;lt;code&amp;gt;SP SB&amp;lt;/code&amp;gt;, and imports &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;SP SPCI5&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CUANSI&amp;lt;/code&amp;gt;, with the import table running to its terminator at &amp;lt;code&amp;gt;+0x1B4&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Both families share a common utility layer, which is why their vocabulary overlaps: &amp;lt;code&amp;gt;CUANSI&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUCONV&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUIO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUMEMORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUMISC&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;CUSTO&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;SRASCOMN&amp;lt;/code&amp;gt; for RAS common code.&lt;br /&gt;
&lt;br /&gt;
==== Reading the dependency graph ====&lt;br /&gt;
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 &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; header is worth knowing about.&lt;br /&gt;
&lt;br /&gt;
Doing so reveals a clean pattern. The &#039;&#039;&#039;numbered&#039;&#039;&#039; names — &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;SPCI5&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;MOPT9&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP MOPD1&amp;lt;/code&amp;gt; — are imported by many modules and &#039;&#039;&#039;defined by none&#039;&#039;&#039;. The &#039;&#039;&#039;lettered&#039;&#039;&#039; members of the same families — &amp;lt;code&amp;gt;MOPTA&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTB&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPTC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MOPD2&amp;lt;/code&amp;gt; — each import their immediate predecessor and are present as real modules.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Caveat.&#039;&#039;&#039; The LID identifier at &amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt; of a &amp;lt;code&amp;gt;PGPM&amp;lt;/code&amp;gt; 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 &#039;&#039;contents&#039;&#039; are unaffected, since they come from the headers themselves — but do not quote a byte offset against a specific LID until this is resolved.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. All 632 payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Exactly one payload contains a single &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; in 289&amp;amp;thinsp;KiB, which is a data coincidence, and no payload has a vector table.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state anywhere: no &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt;, no segment or TLB or cache operations, and only LR, CTR and XER touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read 32-byte records from &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# compute the payload start as &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, rather than trusting the offset field;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The meaning of the header bytes at &amp;lt;code&amp;gt;0x004&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x1FF&amp;lt;/code&amp;gt;, and of the four-byte preamble before &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=SRC&amp;diff=1772</id>
		<title>SRC</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=SRC&amp;diff=1772"/>
		<updated>2026-08-08T17:05:36Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Document the SRC concept and the method for tracing a reference code back to a LIC module (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A &#039;&#039;&#039;system reference code&#039;&#039;&#039; (&#039;&#039;&#039;SRC&#039;&#039;&#039;) is the AS/400&#039;s primary way of telling you what it is doing or what went wrong. It is the string of hexadecimal characters shown on the operator panel&#039;s display, and the same codes appear in the system&#039;s logs and on the console. Because the platform is designed to be serviced by someone who may not have a working console, the SRC is deliberately the lowest-common-denominator channel: it works when nothing else does.&lt;br /&gt;
&lt;br /&gt;
This article covers what an SRC &#039;&#039;is&#039;&#039; and, more usefully, &#039;&#039;&#039;how to work back from one to the piece of Licensed Internal Code that produced it&#039;&#039;&#039;. Individual codes are catalogued elsewhere — see [[Disk device related system reference codes]], [[Tape device related system reference codes]] and [[SRC 0000BBBB]] for worked cases.&lt;br /&gt;
&lt;br /&gt;
== What an SRC looks like ==&lt;br /&gt;
The panel displays eight hexadecimal characters. That display is only the first of several &#039;&#039;words&#039;&#039; the machine has available; the remainder are reached with the panel&#039;s extended functions, and all of them are recorded in the logs.&lt;br /&gt;
&lt;br /&gt;
The leading character is the most informative part, because it identifies what kind of event you are looking at:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Leading character&lt;br /&gt;
!Meaning&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
|Attended IPL — the machine is waiting for you&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt;&lt;br /&gt;
|A problem was detected, most often by Licensed Internal Code&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt;&lt;br /&gt;
|IPL progress; the machine is working normally&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt;&lt;br /&gt;
|Power-down progress&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The distinction that matters when something appears stuck is between &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt;. A &amp;lt;code&amp;gt;C&amp;lt;/code&amp;gt; code is a progress report, and a machine sitting on one for a long time may simply be doing something slow. A &amp;lt;code&amp;gt;B&amp;lt;/code&amp;gt; code is a failure, and it will not clear itself.&lt;br /&gt;
&lt;br /&gt;
Progress codes are genuinely informative about sequence. The IPL-time verification sequence, for instance, runs:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!SRC&lt;br /&gt;
!Meaning&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 4500&amp;lt;/code&amp;gt;&lt;br /&gt;
|Verifying network attributes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 4504&amp;lt;/code&amp;gt;&lt;br /&gt;
|Verifying system serial number&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 4505&amp;lt;/code&amp;gt;&lt;br /&gt;
|Verifying system type&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 4506&amp;lt;/code&amp;gt;&lt;br /&gt;
|Verifying system-unique ID&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 4507&amp;lt;/code&amp;gt;&lt;br /&gt;
|Starting &#039;before DST&#039; DASD checker&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 4508&amp;lt;/code&amp;gt;&lt;br /&gt;
|Verifying system password&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;C600 450A&amp;lt;/code&amp;gt;&lt;br /&gt;
|Starting &#039;after DST&#039; DASD checker&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Read as a whole, that tells you the order of dependency inside the IPL — serial number, then type, then unique ID, then disk state, then the system password — which is information you will not find stated anywhere as prose. Progress codes are a free execution trace of the boot path, and reading a long capture of them is a cheap way to understand a sequence you cannot otherwise observe.&lt;br /&gt;
&lt;br /&gt;
== Where SRCs are recorded ==&lt;br /&gt;
The panel shows the current one. Everything else is in the machine:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Panel extended functions&#039;&#039;&#039; step through the additional words of the current SRC.&lt;br /&gt;
* The &#039;&#039;&#039;Product Activity Log&#039;&#039;&#039;, under DST or SST, holds hardware-detected events with their full word set and timestamps.&lt;br /&gt;
* The &#039;&#039;&#039;Licensed Internal Code log&#039;&#039;&#039; holds LIC-detected events. This is the one that matters for the technique below, because for a LIC-detected error it records the failing &#039;&#039;&#039;module&#039;&#039;&#039; — not just a code.&lt;br /&gt;
* &#039;&#039;&#039;Main storage dumps&#039;&#039;&#039; capture machine state at the point of failure.&lt;br /&gt;
&lt;br /&gt;
If you are trying to understand a failure rather than merely clear it, go to the logs. The panel gives you one word of what may be a nine-word record.&lt;br /&gt;
&lt;br /&gt;
== How SRCs are produced ==&lt;br /&gt;
Inside SLIC there is a family of classes that construct reference codes, one per flavour of event:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
IoMFSystemRefCode                 base&lt;br /&gt;
IoMFGenericSystemRefCode          generic&lt;br /&gt;
IoMFAttentionSystemRefCode        attention&lt;br /&gt;
IoMFIplStatusSystemRefCode        IPL status&lt;br /&gt;
IoMFRunStatusSystemRefCode        run-time status&lt;br /&gt;
IoMFTerminalSystemRefCode         terminal&lt;br /&gt;
IoMFExtendedSrc / IoMFExtendedSrcHyp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
alongside a set of categories that amount to the machine&#039;s error taxonomy — &amp;lt;code&amp;gt;IoMFSrcDeviceFailure&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IoMFSrcIoError&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IoMFSrcIopCodeDetectedFailure&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IoMFSrcSlicDetectedError&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IoMFSrcIopFailureNoDeviceVpd&amp;lt;/code&amp;gt; and several more. Persistent logging goes through an entry point named &amp;lt;code&amp;gt;putSrc&amp;lt;/code&amp;gt; on the persistent-machine class.&lt;br /&gt;
&lt;br /&gt;
Getting the code onto the panel is a separate step, handled by a request/acknowledge message protocol to the service processor. The panel-related messages include &amp;lt;code&amp;gt;IoMFCEMessageSRCDisplay&amp;lt;/code&amp;gt; to display a code and &amp;lt;code&amp;gt;IoMFCEMessagePNLClearSRC&amp;lt;/code&amp;gt; to clear it, in among messages for panel button notifications, power control and IPL mode. The panel is a small subassembly with its own microcontroller, driven over what appears from the software side to be a simple serial link.&lt;br /&gt;
&lt;br /&gt;
The practical consequence is that &#039;&#039;&#039;posting an SRC is an ordinary function call&#039;&#039;&#039; made from ordinary code. It is not a hardware trap or a magic register. So the code that posted a given SRC is findable by the same means as any other caller.&lt;br /&gt;
&lt;br /&gt;
== Working back from an SRC to a LIC module ==&lt;br /&gt;
This is the part worth generalising, because the same route serves any question of the form &amp;quot;which code did this?&amp;quot; — not only SRCs.&lt;br /&gt;
&lt;br /&gt;
=== On the machine ===&lt;br /&gt;
For a LIC-detected error, the Licensed Internal Code log entry names the failing module directly. That is the short path and should always be tried first: DST or SST, the LIC log, then the detailed display for the entry in question. You are looking for a module name and an offset within it.&lt;br /&gt;
&lt;br /&gt;
Module names follow visible conventions once you have seen a few. Names beginning with &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ symbols and are mangled, so a name like &amp;lt;code&amp;gt;putSrc__16NuPersistMachineFUtPv&amp;lt;/code&amp;gt; decomposes into a method &amp;lt;code&amp;gt;putSrc&amp;lt;/code&amp;gt; on class &amp;lt;code&amp;gt;NuPersistMachine&amp;lt;/code&amp;gt; taking an unsigned halfword and a pointer.&lt;br /&gt;
&lt;br /&gt;
=== Offline, from installation media ===&lt;br /&gt;
When the log does not name a module, or when you want to read the code rather than just identify it, the route runs through [[System Files:QFILEMCD]]:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Extract the segments.&#039;&#039;&#039; &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; contains SLIC as large memory segments stored at the addresses the link loader maps them to.&lt;br /&gt;
# &#039;&#039;&#039;Build a name index.&#039;&#039;&#039; Two structures in the code give you addresses paired with names. Every compilation unit ends with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; traceback trailer, many carrying the unit&#039;s name; and the link loader leaves a descriptor block per procedure, with the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name in EBCDIC at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Merging both across every segment of a V4R4 image gives on the order of 184,000 named records.&lt;br /&gt;
# &#039;&#039;&#039;Look the address up.&#039;&#039;&#039; Prefer descriptor hits, which name exactly one procedure, over traceback hits, which cover a whole compilation unit and so only tell you which module an address is in.&lt;br /&gt;
# &#039;&#039;&#039;Find who posts the code.&#039;&#039;&#039; Because SRC posting is a normal call, you can find every site that posts one by resolving the calls to the &amp;lt;code&amp;gt;IoMF*SystemRefCode&amp;lt;/code&amp;gt; constructors and reading what the caller places in the code fields just beforehand.&lt;br /&gt;
&lt;br /&gt;
Step 4 needs one piece of SLIC-specific knowledge. External calls do not go through a dispatch table you can read off. A call is &amp;lt;code&amp;gt;ori r11,r13,&#039;&#039;ordinal&#039;&#039;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into a transfer vector at the top of the address space, and the 16-byte stub it lands on computes the target arithmetically from the ordinal. To resolve calls you need the stub constants, which are not derivable and must be read from a dump of the transfer vector segment. With them, every external call in a segment resolves mechanically.&lt;br /&gt;
&lt;br /&gt;
=== A worked example ===&lt;br /&gt;
The DST module that verifies the system password illustrates the whole path. Immediately before it calls &amp;lt;code&amp;gt;IoMFGenericSystemRefCode&amp;lt;/code&amp;gt;, it does this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
li    r0,  0x12                  ; 18&lt;br /&gt;
li    r31, 0x21                  ; 33&lt;br /&gt;
lhz   r6,  0x18(r29)             ; the password status halfword&lt;br /&gt;
cmpwi r6,  0x30&lt;br /&gt;
bne   ...&lt;br /&gt;
sth   r0,  0x44(r1)              ; status == 0x30 -&amp;gt; code 0x12&lt;br /&gt;
b     ...&lt;br /&gt;
sth   r31, 0x44(r1)              ; otherwise      -&amp;gt; code 0x21&lt;br /&gt;
ori   r11, r13, 0xd45c&lt;br /&gt;
bla   ...                        ; IoMFGenericSystemRefCode&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read backwards, this is exactly the inference you want to be able to make. The reference code is chosen from a status halfword; a status of &amp;lt;code&amp;gt;0x30&amp;lt;/code&amp;gt; produces one code and anything else produces another. So the two codes are not two unrelated faults but two branches of one test, and knowing which one appeared tells you which branch was taken. Working &#039;&#039;forward&#039;&#039; from the SRC list would never reveal that relationship.&lt;br /&gt;
&lt;br /&gt;
=== What the method will not give you ===&lt;br /&gt;
Two honest limits. A traceback trailer names a compilation unit, which may contain many entry points, so it localises rather than pinpoints. And addresses are per-&#039;&#039;&#039;build&#039;&#039;&#039;, not per-release: the same class sits at a completely different address on a machine of another build, so a name index is only valid against the media it was built from. Always match your extracted image to the machine you are investigating, using the build label carried in both container files.&lt;br /&gt;
&lt;br /&gt;
== Why this is worth learning ==&lt;br /&gt;
The technique generalises well beyond diagnosing faults. An SRC sequence is an execution trace with names attached, and the machine emits one on every IPL whether or not anything is wrong. Combined with a name index over the LIC image, it lets you ask questions the documentation does not answer — what the machine checks and in what order, which subsystem owns a given behaviour, where a slow phase is actually spending its time — using only a panel display and a copy of the installation media.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEMCD]]&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC 0000BBBB]]&lt;br /&gt;
* [[Disk device related system reference codes]]&lt;br /&gt;
* [[Tape device related system reference codes]]&lt;br /&gt;
* [[Panel Usage]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.ibm.com/docs/en/i/7.4.0?topic=finder-system-reference-code-list System reference code list], IBM Documentation&lt;br /&gt;
* [https://www.ibm.com/resources/publications/OutputPubsDetails?PubID=SY44590100 AS/400e Service Functions], which documents the panel functions and the IPL progress code sequences&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEMCD&amp;diff=1771</id>
		<title>System Files:QFILEMCD</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEMCD&amp;diff=1771"/>
		<updated>2026-08-08T17:04:39Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Document the QFILEMCD / COPYDIR container: header, directory, segment extraction (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;&#039;&#039;&#039; is the larger of the two container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It is a backup of &#039;&#039;&#039;SLIC&#039;&#039;&#039; itself — the System Licensed Internal Code that sits below OS/400 — stored as a small number of very large memory segments. Its internal format is called &#039;&#039;&#039;&amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;&#039;&#039;&#039; after the eyecatcher at offset zero.&lt;br /&gt;
&lt;br /&gt;
Practically, this is the file to reach for if you want to read the machine&#039;s own code without touching a running system. Its segments are a byte-for-byte image of what the link loader maps into memory, so an address recovered from a crash, a trace or a [[SRC|system reference code]] can be looked up directly in a file on your workstation. The companion file [[System Files:QFILEIML]] carries the loadable IOP, adapter and service processor microcode instead.&lt;br /&gt;
&lt;br /&gt;
Both files are containers of [[Data Structures:LID|LIDs]], but at different granularities, and the relationship between them is described under &#039;&#039;Two directories, two granularities&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
The figures quoted here come from one V4R4 image of 472,846,336 bytes (451&amp;amp;thinsp;MiB). Treat structure as general and numbers as release-specific; the format is known to have survived at least to V7R2 with the same shape.&lt;br /&gt;
&lt;br /&gt;
== Header ==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|Eyecatcher &amp;lt;code&amp;gt;COPYDIR&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC (&amp;lt;code&amp;gt;C3 D6 D7 E8 C4 C9 D9 40&amp;lt;/code&amp;gt;), a zero byte, then the two EBCDIC characters &amp;lt;code&amp;gt;00&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|32-bit total size of the payload area — see below&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x26&amp;lt;/code&amp;gt;&lt;br /&gt;
|Release and build string, EBCDIC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x50&amp;lt;/code&amp;gt;&lt;br /&gt;
|Licensed Internal Code banner, EBCDIC, in 48-character chunks&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;&lt;br /&gt;
|Start of the directory&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The release string in this image is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
V4R4M044-C6295  2606071417&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first part identifies the release and build. The ten digits that follow parse naturally as a timestamp of the form &amp;lt;code&amp;gt;YYMMDDHHMM&amp;lt;/code&amp;gt;, which would make this backup 2026-06-07 14:17 — plausible, since the image was produced by a SAVSYS on a running machine rather than shipped by IBM. That reading is an inference from the shape of the field.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The header is &#039;&#039;&#039;not&#039;&#039;&#039; a fixed 192 (&amp;lt;code&amp;gt;0xC0&amp;lt;/code&amp;gt;) bytes, despite older format notes saying so. The IBM legal banner runs on well past that point, and in this V4R4 image the directory does not begin until &amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;. A parser should locate the directory by scanning for the first 64-byte-aligned block that has the shape of an entry, rather than seeking to a constant.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 32-bit field at &amp;lt;code&amp;gt;0x1C&amp;lt;/code&amp;gt; holds &amp;lt;code&amp;gt;0x1C2F0000&amp;lt;/code&amp;gt;, which is exactly the end of the last segment&#039;s data. It is a total-payload-size field and makes a good consistency check after parsing the directory: accumulate the entries and you should arrive at the same number.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory is a run of 64-byte entries beginning at &amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Flags. See the bit-numbering warning below&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|SLS address of the saved segment&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Segment attributes; the top 16 bits carry the useful value&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x20&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x28&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Offset to the segment data, &#039;&#039;&#039;absolute from the start of the file&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x30&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Segment length, in &#039;&#039;&#039;raw bytes&#039;&#039;&#039; — not blocks&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x34&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|Always zero in observed data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two details cause most of the trouble people have with this structure, and both were originally got wrong here:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Flags use IBM&#039;s MSB-first bit numbering.&#039;&#039;&#039; Older notes describe the field as &amp;lt;code&amp;gt;bbt 0:3&amp;lt;/code&amp;gt;, and a reader used to LSB-first numbering will look in the bottom nibble and find nothing. Bit 0 is the &#039;&#039;most&#039;&#039; significant bit, so the value lives in the &#039;&#039;&#039;top&#039;&#039;&#039; nibble of the 8-byte field. A normal entry reads &amp;lt;code&amp;gt;0x1000000000000000&amp;lt;/code&amp;gt;; the end-of-directory marker reads &amp;lt;code&amp;gt;0xF000000000000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;The data offset is absolute.&#039;&#039;&#039; It is measured from the start of the file, not from the end of the directory. Reading it as relative shifts every extracted segment by the size of the directory, which produces code that disassembles almost plausibly and is wrong everywhere.&lt;br /&gt;
&lt;br /&gt;
In this image the directory holds &#039;&#039;&#039;32 entries&#039;&#039;&#039;, with the terminator at &amp;lt;code&amp;gt;0x9C0&amp;lt;/code&amp;gt; and the directory ending at &amp;lt;code&amp;gt;0xA00&amp;lt;/code&amp;gt;. The first entry has a data offset of zero, which means the header and directory physically occupy the first &amp;lt;code&amp;gt;0xA00&amp;lt;/code&amp;gt; bytes of the first segment&#039;s stored image. This is expected rather than a bug, but a tool that extracts that segment will see the container&#039;s own header at the front of it.&lt;br /&gt;
&lt;br /&gt;
Segment lengths are consistently a whole number of 4&amp;amp;thinsp;KiB pages less than a power-of-two boundary: &amp;lt;code&amp;gt;0xFFF000&amp;lt;/code&amp;gt; is 16&amp;amp;thinsp;MiB minus one page, &amp;lt;code&amp;gt;0x7FF000&amp;lt;/code&amp;gt; is 8&amp;amp;thinsp;MiB minus one page, and so on.&lt;br /&gt;
&lt;br /&gt;
== Contents of a typical backup ==&lt;br /&gt;
The 32 segments of this image, with names from a community-maintained SLS address reference. Where the name column is blank, the segment&#039;s purpose has not been established.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!SLS address&lt;br /&gt;
!Length&lt;br /&gt;
!Name&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB3 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFB5 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC3 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (2)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC4 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (3)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC5 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (4)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC6 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader — LIC Code (5)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC7 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Mixed — component code and NLS text pools&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFC8 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|Mixed — bignum/JVM code and NLS text pools&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFF1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader TOC&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFF2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Service LID&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFF4 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Service LID (2)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFFE 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|15&amp;amp;thinsp;MiB&lt;br /&gt;
|Pageable BLA&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader Information&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader Information, Code, Data&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD3 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Link Loader Information (2)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFD4 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|Mixed — JVM strings and DST debug symbol table&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF90 010000&amp;lt;/code&amp;gt;&lt;br /&gt;
|60&amp;amp;thinsp;KiB&lt;br /&gt;
|LID Directory&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF91 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC2 A-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF92 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC2 B-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF93 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC1 A-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF94 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID NUC1 B-Side&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF95 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF96 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF9A 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF9B 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFA1 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|LID Manager&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFFA2 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;FFFFFFFF69 000000&amp;lt;/code&amp;gt;&lt;br /&gt;
|16&amp;amp;thinsp;MiB&lt;br /&gt;
|IDE&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
So a backup of this shape is the SLIC boot and loader nucleus: link loader code and data, the loader&#039;s table of contents, the LID subsystem&#039;s own bookkeeping, and both IPL sides of the two nucleus LIDs. It is not the whole of the machine&#039;s code.&lt;br /&gt;
&lt;br /&gt;
=== A and B sides ===&lt;br /&gt;
Several segments appear twice, distinguished as &#039;&#039;A-side&#039;&#039; and &#039;&#039;B-side&#039;&#039;. An AS/400 keeps two copies of its Licensed Internal Code so that an update can be applied to one while the other remains a fallback. A normal, unattended IPL runs the &#039;&#039;&#039;B side&#039;&#039;&#039;, so B is what a running machine is executing and B is what static analysis should be done against. Because the two sides are normally near-identical, a byte comparison against the A side is not evidence that A is the live one — the test only means something on a segment that actually differs between them.&lt;br /&gt;
&lt;br /&gt;
== Two directories, two granularities ==&lt;br /&gt;
A common source of confusion is that &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; appears to have two completely different directory formats. It does, and they nest:&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;&#039;coarse&#039;&#039;&#039; level is &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;&#039;s own directory, documented above: 64-byte entries, one per 16&amp;amp;thinsp;MiB-class memory segment, 32 of them.&lt;br /&gt;
* The &#039;&#039;&#039;fine&#039;&#039;&#039; level is a catalogue of individual LIDs, thousands of entries, using the 32-byte record described at [[Data Structures:LID]].&lt;br /&gt;
&lt;br /&gt;
The fine level is not a second header in the file. It is simply &#039;&#039;&#039;the contents of one particular segment&#039;&#039;&#039; — the one named &#039;&#039;LID Directory&#039;&#039;, at &amp;lt;code&amp;gt;FFFFFFFF90 010000&amp;lt;/code&amp;gt;. Extract that segment and you find, after a preamble of about 1536 bytes, an EBCDIC &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt; eyecatcher, a version label, and then the records. In this image the label reads &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;, which is the same label carried by [[System Files:QFILEIML]] — a quick way to confirm that two files came off the same media.&lt;br /&gt;
&lt;br /&gt;
That is also why tools which dump this file emit two dissimilar-looking listings: a short table of large memory extents, and a long list of LIDs. They are two levels of one structure, not two formats.&lt;br /&gt;
&lt;br /&gt;
== Extracting a segment ==&lt;br /&gt;
The practical recipe, and the reason this file is worth knowing about:&lt;br /&gt;
&lt;br /&gt;
# Read the &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt; eyecatcher at offset 0 to confirm the format.&lt;br /&gt;
# Find the directory by scanning 64-byte-aligned offsets for the first entry-shaped block, rather than assuming &amp;lt;code&amp;gt;0xC0&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;0x1C0&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Walk entries until the flags field has &amp;lt;code&amp;gt;0xF&amp;lt;/code&amp;gt; in its &#039;&#039;&#039;top&#039;&#039;&#039; nibble.&lt;br /&gt;
# For the segment you want, seek to the data offset &#039;&#039;&#039;as an absolute file offset&#039;&#039;&#039; and read &#039;&#039;length&#039;&#039; raw bytes.&lt;br /&gt;
# Load the result at its SLS address in a disassembler. The bytes are what the link loader maps, so addresses match.&lt;br /&gt;
&lt;br /&gt;
Step 5 is the payoff. A 64-bit address such as &amp;lt;code&amp;gt;FFFFFFFFC6 1F1690&amp;lt;/code&amp;gt; can be typed straight into the DST &#039;&#039;Display/Alter storage&#039;&#039; panel on a live machine of the same build, and the sixteen rows it displays will match the extracted file byte for byte. Static and live analysis share one address space, which means you can do the slow work offline and use the machine only for confirmation.&lt;br /&gt;
&lt;br /&gt;
Two caveats on addresses. They are per-&#039;&#039;&#039;build&#039;&#039;&#039;, not per-release, so comparisons are only meaningful between identical builds; the same class sits at a quite different address on a V5R4 machine. And the SLS address recorded in the directory is the address the segment was &#039;&#039;&#039;saved from&#039;&#039;&#039;, which is not always where it runs — the resident nucleus segment, for instance, is stored in the container under the SID of the B-side nucleus LID rather than its runtime SID.&lt;br /&gt;
&lt;br /&gt;
== Reading the code ==&lt;br /&gt;
Once a segment is loaded, two structures make it navigable, and both are worth knowing because they turn addresses into names:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Traceback trailers.&#039;&#039;&#039; Every compilation unit ends its code with a &amp;lt;code&amp;gt;TBTB&amp;lt;/code&amp;gt; trailer, and many carry the module&#039;s name. A trailer names a whole compilation unit rather than a single function, so a hit means &amp;quot;this address is inside module X&amp;quot;, not &amp;quot;this address is function X&amp;quot;.&lt;br /&gt;
* &#039;&#039;&#039;Link-loader descriptor blocks.&#039;&#039;&#039; Considerably richer: one block per procedure, carrying the entry address at &amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt; and the name in EBCDIC at &amp;lt;code&amp;gt;+0x38&amp;lt;/code&amp;gt;. Names beginning with &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; are SLIC-internal modules; the rest are C++ mangled symbols.&lt;br /&gt;
&lt;br /&gt;
Merging both across every segment of this V4R4 image yields roughly 184,000 named records, which is enough to name a substantial fraction of any address you encounter. See [[SRC]] for how to use that to get from a reference code back to a module.&lt;br /&gt;
&lt;br /&gt;
Calls between modules do not go through a conventional dispatch table, which surprises people disassembling SLIC for the first time. An external call is a two-instruction sequence — &amp;lt;code&amp;gt;ori r11,r13,&#039;&#039;ordinal&#039;&#039;&amp;lt;/code&amp;gt; followed by &amp;lt;code&amp;gt;bla&amp;lt;/code&amp;gt; into a transfer vector at the very top of the address space — and the 16-byte stub it lands on computes the target arithmetically. There is no table to read off; the ordinal &#039;&#039;is&#039;&#039; the callee&#039;s word offset within a window, and the stub supplies the window. The stub constants cannot be derived and must be read from a dump of the transfer vector.&lt;br /&gt;
&lt;br /&gt;
== The trailing page ==&lt;br /&gt;
The payload area ends at &amp;lt;code&amp;gt;0x1C2F0000&amp;lt;/code&amp;gt;, but the file is one 4&amp;amp;thinsp;KiB page longer than that. The final page is not padding: it holds 468 non-zero 8-byte records, which appear to be address-and-value pairs.&lt;br /&gt;
&lt;br /&gt;
They fall into two clear populations. The first 110 are in ascending address order with a value of 8, addressing the &#039;&#039;Link Loader — LIC Data&#039;&#039; segment among others. The remaining 256 are identical to each other: the same address &amp;lt;code&amp;gt;0xFE911220&amp;lt;/code&amp;gt;, in the &#039;&#039;Pageable BLA&#039;&#039; segment, paired with the value &amp;lt;code&amp;gt;0x48000002&amp;lt;/code&amp;gt; — which as PowerPC is a branch-absolute to zero, the shape of a deliberately poisoned entry.&lt;br /&gt;
&lt;br /&gt;
This has the flavour of a fixup or relocation list applied after the segments are restored, but that is a guess from shape alone. It is recorded here because it is real, reproducible and unexplained, and because a parser that assumes the file ends with the payload will silently ignore it.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The purpose of the trailing page.&lt;br /&gt;
* The header bytes other than the eyecatcher, size field, release string and banner.&lt;br /&gt;
* The meaning of the segment attribute field&#039;s top 16 bits, which take values &amp;lt;code&amp;gt;0x0001&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0040&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x0080&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;0x0100&amp;lt;/code&amp;gt; and correlate loosely with segment size.&lt;br /&gt;
* Names for the nine segments left blank in the table above.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[SRC]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1770</id>
		<title>System Files:QFILEIML</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=System_Files:QFILEIML&amp;diff=1770"/>
		<updated>2026-08-08T16:57:53Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Document the QFILEIML / IMD1 container: layout, directory, payload addressing, contents (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;&amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;&#039;&#039;&#039; is one of the two large container files found on AS/400 SAVSYS and Licensed Internal Code installation media. It holds the machine&#039;s &#039;&#039;loadable&#039;&#039; microcode: IOP and adapter firmware, service processor firmware, and a quantity of SLIC modules. Its internal format is identified by the four-byte magic &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039; and is a container of [[Data Structures:LID|LIDs]].&lt;br /&gt;
&lt;br /&gt;
The companion file &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; holds SLIC proper, via a directory called &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;. Both files use the same 32-byte [[Data Structures:LID|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.&lt;br /&gt;
&lt;br /&gt;
The name is not documented by IBM as far as is known here. &amp;lt;code&amp;gt;IML&amp;lt;/code&amp;gt; almost certainly stands for &#039;&#039;Initial Microprogram Load&#039;&#039; — the phase in which the machine&#039;s microcode is brought up, before OS/400 itself exists — which matches the file&#039;s contents. Treat the expansion as an inference.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; of 81,287,680 bytes (77.5&amp;amp;thinsp;MiB), build label &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== File layout ==&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x000&amp;lt;/code&amp;gt;&lt;br /&gt;
|Magic &amp;lt;code&amp;gt;C9 D4 C4 F1&amp;lt;/code&amp;gt;, which is &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; in EBCDIC, followed by a short and largely unexplored header&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt;&lt;br /&gt;
|Licensed Internal Code banner in EBCDIC, carrying the LIC product identifiers&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x400&amp;lt;/code&amp;gt;&lt;br /&gt;
|Directory header: a four-byte preamble, the literal string &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;, two zero bytes, then a 16-byte build label&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;&lt;br /&gt;
|The directory: a run of 32-byte LID records&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;varies&#039;&#039;&lt;br /&gt;
|Terminator record, identifier &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; in EBCDIC)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;&lt;br /&gt;
|Payload area&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The first sixteen bytes of the file are:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000000: c9d4 c4f1 0000 0000 ff00 0200 00e0 0000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The banner at &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; reads, in EBCDIC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
LICENSED INTERNAL CODE - PROPERTY OF IBM 5763999, 5716999, 5769999&lt;br /&gt;
(C) COPYRIGHT IBM CORP. 1980, 1998. ALL RIGHTS RESERVED. ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The three seven-digit numbers are LIC product identifiers, and the same three appear in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;. The build label at &amp;lt;code&amp;gt;0x410&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;v4r4m01204.0.03&amp;lt;/code&amp;gt;, likewise identical between the two files, which is a convenient way to confirm that a given &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; came off the same media.&lt;br /&gt;
&lt;br /&gt;
== The directory ==&lt;br /&gt;
The directory begins at &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; and runs, in this image, for 632 records before the &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt; terminator at &amp;lt;code&amp;gt;0x5320&amp;lt;/code&amp;gt;. The record layout is documented at [[Data Structures:LID]] and is not repeated here.&lt;br /&gt;
&lt;br /&gt;
Of the 632 records:&lt;br /&gt;
* 341 carry the compressed flag.&lt;br /&gt;
* 631 name an SLS staging address in the &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band. Exactly one does not: LID &amp;lt;code&amp;gt;80900818&amp;lt;/code&amp;gt; stages at &amp;lt;code&amp;gt;000000024A 000000&amp;lt;/code&amp;gt;.&lt;br /&gt;
* 7 have payloads that are themselves runs of LID records — see &#039;&#039;Directory extents&#039;&#039; below.&lt;br /&gt;
&lt;br /&gt;
== Payload addressing ==&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; This is the single point on which it is easiest to go wrong, and doing so silently produces plausible-looking nonsense.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;offset&amp;lt;/code&amp;gt; field in each record is &#039;&#039;&#039;not&#039;&#039;&#039; an offset into &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;. 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The actual rule is simpler: &#039;&#039;&#039;payloads are stored sequentially, in directory order, immediately after the directory&#039;&#039;&#039;, each one &amp;lt;code&amp;gt;length&amp;lt;/code&amp;gt; blocks long. There are no gaps and no padding between them.&lt;br /&gt;
&lt;br /&gt;
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, &amp;lt;code&amp;gt;0x5400&amp;lt;/code&amp;gt;, immediately past the directory terminator — and the payloads then tile to the final byte of the file with nothing left over.&lt;br /&gt;
&lt;br /&gt;
To locate a payload, therefore, walk the directory from the beginning and accumulate lengths; do not index by the offset field.&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
Laid out correctly, the payloads fall into two clear populations, distinguishable without decompression by looking for 32-bit &amp;lt;code&amp;gt;stwu r1,-x(r1)&amp;lt;/code&amp;gt; prologues versus 64-bit &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; stores:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Population&lt;br /&gt;
!Count&lt;br /&gt;
!Identification&lt;br /&gt;
|-&lt;br /&gt;
|32-bit PowerPC&lt;br /&gt;
|75&lt;br /&gt;
|&amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; prologues present, no &amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|64-bit PowerPC AS (SLIC)&lt;br /&gt;
|210&lt;br /&gt;
|&amp;lt;code&amp;gt;std&amp;lt;/code&amp;gt; present, no &amp;lt;code&amp;gt;stwu&amp;lt;/code&amp;gt; at all&lt;br /&gt;
|-&lt;br /&gt;
|Neither&lt;br /&gt;
|347&lt;br /&gt;
|Compressed payloads, data, tables, and directory extents&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Service processor firmware ===&lt;br /&gt;
LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; is service processor Licensed Internal Code: 128&amp;amp;thinsp;KiB, stored uncompressed, staged at SLS &amp;lt;code&amp;gt;FFFFFFFF9A 001000&amp;lt;/code&amp;gt;. Its EBCDIC strings include a &#039;&#039;9400 Licensed Internal Code&#039;&#039; banner, a 1998 copyright, and a table of component tags of the form &amp;lt;code&amp;gt;SP MOPT1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP SPCI1&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP SBL&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SP SM&amp;lt;/code&amp;gt; and so on, alongside build identifiers such as &amp;lt;code&amp;gt;AJSFGWC3&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AJSRWP32&amp;lt;/code&amp;gt;. Its code is unambiguously 32-bit.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The picture is more subtle than &amp;quot;the service processor firmware is in this file&amp;quot;, however. Scanning all 632 payloads for the LIC banner, a &amp;lt;code&amp;gt;SP&amp;amp;nbsp;&amp;lt;/code&amp;gt; component tag table and a 32-bit-only instruction profile finds roughly 19 such images, ranging from 34&amp;amp;thinsp;KiB to 395&amp;amp;thinsp;KiB, with differing component-tag sets — which is what one would expect of capability tiers across a hardware range where the service processor is entirely invisible to the user.&lt;br /&gt;
&lt;br /&gt;
Those images separate cleanly into two families by their build identifier prefix, and no image carries both prefixes:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Family&lt;br /&gt;
!Count&lt;br /&gt;
!Build ID prefix&lt;br /&gt;
!Distinguishing markers&lt;br /&gt;
|-&lt;br /&gt;
|Service processor&lt;br /&gt;
|16&lt;br /&gt;
|&amp;lt;code&amp;gt;AJS…&amp;lt;/code&amp;gt;&lt;br /&gt;
|8 to 24 &amp;lt;code&amp;gt;SP&amp;amp;nbsp;&amp;lt;/code&amp;gt; component tags per image&lt;br /&gt;
|-&lt;br /&gt;
|I/O offload (MFIOP)&lt;br /&gt;
|6&lt;br /&gt;
|&amp;lt;code&amp;gt;AJG…&amp;lt;/code&amp;gt;&lt;br /&gt;
|No &amp;lt;code&amp;gt;SP&amp;amp;nbsp;&amp;lt;/code&amp;gt; tags at all; several carry an &amp;lt;code&amp;gt;ATM&amp;lt;/code&amp;gt; marker, i.e. ATM networking code&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Both families share a common runtime library — tags &amp;lt;code&amp;gt;CUANSI&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUCONV&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUIO&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUMEMORY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUMISC&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CUSTO&amp;lt;/code&amp;gt;, plus &amp;lt;code&amp;gt;SRASCOMN&amp;lt;/code&amp;gt; for RAS common code — which is why their vocabulary overlaps and why the build-ID prefix, rather than the string content, is the reliable discriminator.&lt;br /&gt;
&lt;br /&gt;
=== What is not in the file ===&lt;br /&gt;
Notably, the service processor&#039;s own &#039;&#039;&#039;supervisor is absent&#039;&#039;&#039;. All 632 payloads were searched for &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;0x4C000064&amp;lt;/code&amp;gt;), which any PowerPC exception-returning kernel must contain, and for exception vector tables at the architectural &amp;lt;code&amp;gt;0x100&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;0x200&amp;lt;/code&amp;gt; and subsequent offsets of every 4&amp;amp;thinsp;KiB boundary. Exactly one payload contains a single &amp;lt;code&amp;gt;rfi&amp;lt;/code&amp;gt; in 289&amp;amp;thinsp;KiB, which is a data coincidence, and no payload has a vector table.&lt;br /&gt;
&lt;br /&gt;
Consistent with that, LID &amp;lt;code&amp;gt;80900702&amp;lt;/code&amp;gt; begins mid-function, with a function &#039;&#039;tail&#039;&#039; rather than an entry point, and manipulates no privileged state anywhere: no &amp;lt;code&amp;gt;mtmsr&amp;lt;/code&amp;gt;, no segment or TLB or cache operations, and only LR, CTR and XER touched. It does contain 31 &amp;lt;code&amp;gt;sc&amp;lt;/code&amp;gt; supervisor calls.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
=== Directory extents ===&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Compression ==&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Tooling ==&lt;br /&gt;
No IBM-supplied tool for reading this file outside the machine is known. A parser must, at minimum:&lt;br /&gt;
# check the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; magic at offset 0;&lt;br /&gt;
# read 32-byte records from &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt; until an identifier of &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt; or zero;&lt;br /&gt;
# compute the payload start as &#039;&#039;file size in blocks minus the sum of all lengths&#039;&#039;, rather than trusting the offset field;&lt;br /&gt;
# lay payloads out sequentially in directory order.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
== Open questions ==&lt;br /&gt;
* The meaning of the header bytes at &amp;lt;code&amp;gt;0x004&amp;lt;/code&amp;gt;–&amp;lt;code&amp;gt;0x1FF&amp;lt;/code&amp;gt;, and of the four-byte preamble before &amp;lt;code&amp;gt;Directory.&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The meaning of most LID identifier families.&lt;br /&gt;
* Why 31 payloads carry the compressed flag yet begin with plainly readable 32-bit code.&lt;br /&gt;
* Whether the load-source LBAs in the offset field can be used to reconstruct the physical layout of the original installation medium.&lt;br /&gt;
* Classification of the remaining 32-bit payloads: several are adapter microcode, but others may be operator panel or SPCN code.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Data Structures:LID]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
* [[Copying disks with Linux]]&lt;br /&gt;
&lt;br /&gt;
== Weblinks ==&lt;br /&gt;
* [https://www.mcpressonline.com/ MC Press Online], which carries older documentation describing service processor microcode as being loaded from the load source&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
	<entry>
		<id>http://try-as400.pocnet.net/index.php?title=Data_Structures:LID&amp;diff=1769</id>
		<title>Data Structures:LID</title>
		<link rel="alternate" type="text/html" href="http://try-as400.pocnet.net/index.php?title=Data_Structures:LID&amp;diff=1769"/>
		<updated>2026-08-08T16:57:06Z</updated>

		<summary type="html">&lt;p&gt;Friedkiwi: Document the LID (Load ID) container record format shared by COPYDIR and IMD1 (via create-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A &#039;&#039;&#039;LID&#039;&#039;&#039; (&#039;&#039;Load ID&#039;&#039;) is IBM&#039;s general-purpose container for shipping a blob of code or data to a machine. It is not specific to any one file, release, or processor architecture: the same 32-byte directory record describes SLIC modules, IOP and adapter microcode, and service processor firmware, and the same idea survives into modern POWER hardware.&lt;br /&gt;
&lt;br /&gt;
Because the record format is shared between several container files, it is documented here once rather than repeated in each. The container that uses it is described in [[System Files:QFILEIML]].&lt;br /&gt;
&lt;br /&gt;
== The directory record ==&lt;br /&gt;
A LID container consists of a header, a directory of fixed 32-byte records, and the payloads. Every record has the following layout. All fields are big endian.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Offset&lt;br /&gt;
!Size&lt;br /&gt;
!Field&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x00&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|LID identifier&lt;br /&gt;
|Not a sequence number. The high halfword is a &#039;&#039;family&#039;&#039; — see below.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x04&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Offset&lt;br /&gt;
|In 512-byte blocks. &#039;&#039;&#039;Base and meaning depend on the container&#039;&#039;&#039; — see the warning below.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x08&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Length&lt;br /&gt;
|In 512-byte blocks.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x0C&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Flags&lt;br /&gt;
|&amp;lt;code&amp;gt;0x80000000&amp;lt;/code&amp;gt; = compressed. No other bit has been observed set.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x10&amp;lt;/code&amp;gt;&lt;br /&gt;
|8&lt;br /&gt;
|SLS address&lt;br /&gt;
|Where the payload is to be staged in single-level store.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x18&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Time&lt;br /&gt;
|Packed BCD &amp;lt;code&amp;gt;HHMM&amp;lt;/code&amp;gt;; read the field as hexadecimal to display it. &amp;lt;code&amp;gt;0x00001757&amp;lt;/code&amp;gt; is 17:57.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;+0x1C&amp;lt;/code&amp;gt;&lt;br /&gt;
|4&lt;br /&gt;
|Date&lt;br /&gt;
|Packed BCD &amp;lt;code&amp;gt;YYYYMMDD&amp;lt;/code&amp;gt;, likewise. &amp;lt;code&amp;gt;0x19970318&amp;lt;/code&amp;gt; is 1997-03-18.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The directory is terminated by a record whose identifier field is &amp;lt;code&amp;gt;0xC5D5C440&amp;lt;/code&amp;gt;, which is the EBCDIC string &amp;lt;code&amp;gt;END&amp;amp;nbsp;&amp;lt;/code&amp;gt;. A zero identifier also terminates.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Note!&#039;&#039;&#039; The &#039;&#039;&#039;offset&#039;&#039;&#039; field is the field most likely to mislead. It is &#039;&#039;not&#039;&#039; universally a byte or block offset into the container file. In the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; container it is a load-source LBA — an address on the installation medium — and is meaningless as a file offset; payloads there are instead laid out sequentially in directory order. See [[System Files:QFILEIML]] for the worked case. Always establish the addressing base for a given container before extracting anything.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Worked example ===&lt;br /&gt;
The first record of the &amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt; directory in a V4R4 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;, at file offset &amp;lt;code&amp;gt;0x420&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
00000420: 8070 0830 0000 0210 0000 0004 0000 0000&lt;br /&gt;
00000430: ffff ffff 9300 1000 0000 1757 1997 0318&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
decodes as LID &amp;lt;code&amp;gt;80700830&amp;lt;/code&amp;gt;, offset block 528, length 4 blocks (2&amp;amp;thinsp;KiB), flags 0 (not compressed), SLS address &amp;lt;code&amp;gt;FFFFFFFF93 001000&amp;lt;/code&amp;gt;, timestamp 1997-03-18 17:57.&lt;br /&gt;
&lt;br /&gt;
That same record appears byte for byte as the sixth LID of &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;&#039;s nested &amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt; LID directory, which is what establishes that the two containers share one record format.&lt;br /&gt;
&lt;br /&gt;
== The SLS address field ==&lt;br /&gt;
The 8-byte address is a single-level store address, split 40/24 into a segment identifier and a byte offset within the segment, so segments are 16&amp;amp;thinsp;MiB. Printed with that split, the example above is segment &amp;lt;code&amp;gt;FFFFFFFF93&amp;lt;/code&amp;gt;, offset &amp;lt;code&amp;gt;0x001000&amp;lt;/code&amp;gt;. This is the same notation the DST &#039;&#039;Display/Alter storage&#039;&#039; panel accepts.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; band is resident Licensed Internal Code. Note that a segment identifier recorded in a directory is the &#039;&#039;load source&#039;&#039; segment — where the payload was saved from, or is staged into — which is not necessarily the segment the code eventually executes in. Payloads destined for an IOP or the service processor are staged into a SLIC segment first and then transferred over the bus to the target card, so an &amp;lt;code&amp;gt;FFFFFFFFxx&amp;lt;/code&amp;gt; address does &#039;&#039;&#039;not&#039;&#039;&#039; imply the payload is SLIC code.&lt;br /&gt;
&lt;br /&gt;
== LID identifier families ==&lt;br /&gt;
The identifier is structured rather than sequential: the high halfword groups LIDs into families, and members of a family share a purpose. In a V4R4 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt; the most populous families are:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Family&lt;br /&gt;
!Records&lt;br /&gt;
!Observed contents&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;a170&amp;lt;/code&amp;gt;&lt;br /&gt;
|144&lt;br /&gt;
|Not established&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;a0b0&amp;lt;/code&amp;gt;&lt;br /&gt;
|66&lt;br /&gt;
|Not established&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;a100&amp;lt;/code&amp;gt;&lt;br /&gt;
|56&lt;br /&gt;
|Not established&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;8190&amp;lt;/code&amp;gt;&lt;br /&gt;
|54&lt;br /&gt;
|Not established&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;a0c0&amp;lt;/code&amp;gt;&lt;br /&gt;
|37&lt;br /&gt;
|Not established&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;8390&amp;lt;/code&amp;gt;&lt;br /&gt;
|36&lt;br /&gt;
|Not established&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;a090&amp;lt;/code&amp;gt;&lt;br /&gt;
|33&lt;br /&gt;
|Largely 32-bit PowerPC firmware images&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;8590&amp;lt;/code&amp;gt;&lt;br /&gt;
|30&lt;br /&gt;
|Largely 32-bit PowerPC firmware images&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;8090&amp;lt;/code&amp;gt;&lt;br /&gt;
|29&lt;br /&gt;
|Mixed; includes the service processor firmware and the two large SLIC LIDs&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The purpose of most families has not been established. The &amp;lt;code&amp;gt;80xxxxxx&amp;lt;/code&amp;gt; range is the only one &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt; uses.&lt;br /&gt;
&lt;br /&gt;
== The compressed flag ==&lt;br /&gt;
Bit &amp;lt;code&amp;gt;0x80000000&amp;lt;/code&amp;gt; marks a payload as compressed. The codec is the LZW variant implemented in SLIC by the routines &amp;lt;code&amp;gt;LZdcomp&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;cpdcomp&amp;lt;/code&amp;gt;, which supports 9-, 10- and 12-bit codes and dispatches on a leading format byte of &amp;lt;code&amp;gt;0x11&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;0x21&amp;lt;/code&amp;gt;. It is &#039;&#039;&#039;not&#039;&#039;&#039; any of the OS/400 &amp;lt;code&amp;gt;*LOW&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*MEDIUM&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;*HIGH&amp;lt;/code&amp;gt; save-file compression methods, nor zlib or raw deflate; all of those have been tried against real payloads and fail immediately.&lt;br /&gt;
&lt;br /&gt;
The flag should be treated as advisory rather than exact. In one V4R4 &amp;lt;code&amp;gt;QFILEIML&amp;lt;/code&amp;gt;, 31 payloads carry the compressed flag yet begin with clean, plainly readable 32-bit PowerPC function prologues. Whatever the flag governs, it is not a simple &amp;quot;this entire payload is one compressed stream&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Containers and consumers ==&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;COPYDIR&amp;lt;/code&amp;gt;&#039;&#039;&#039;, the directory in &amp;lt;code&amp;gt;QFILEMCD&amp;lt;/code&amp;gt;, carries SLIC itself as a nested LID directory.&lt;br /&gt;
* &#039;&#039;&#039;&amp;lt;code&amp;gt;IMD1&amp;lt;/code&amp;gt;&#039;&#039;&#039;, the format of [[System Files:QFILEIML]], carries IOP, adapter and service processor microcode alongside SLIC modules.&lt;br /&gt;
* SLIC contains an interactive &#039;&#039;&#039;LID filesystem&#039;&#039;&#039;. The commands &amp;lt;code&amp;gt;IdeLidFileSystem&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IdeCopyLidCmd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IdeFindLidCmd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IdeVerifyLid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IdeCompressLidCmd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IdeDecompressLidCmd&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IdeLidListCmd&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;IdeMakeTempLidCmd&amp;lt;/code&amp;gt; all appear in a V4R4 name index, so a LID is a first-class object to the machine rather than merely an installation-media artefact.&lt;br /&gt;
* Adapter and IOP classes in SLIC expose a &amp;lt;code&amp;gt;downLoadLid&amp;lt;/code&amp;gt; method, which is the mechanism by which a staged LID reaches the card.&lt;br /&gt;
* On modern POWER hardware the &#039;&#039;&#039;flexible service processor&#039;&#039;&#039; holds a filesystem of LIDs containing the hypervisor, the Open Firmware image used by AIX and Linux partitions, the component that replaces the physical front panel, and adapter firmware for several third-party network and storage cards.&amp;lt;ref&amp;gt;Reported by a machine owner familiar with FSP internals; not independently verified here, but consistent with IBM&#039;s evident reuse of the container across generations.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Scope of this description ==&lt;br /&gt;
Everything above was read from a single V4R4 installation image and cross-checked between its two container files. Field offsets, sizes and the terminator are considered established. Family meanings, and the exact semantics of the compressed flag, are not.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[System Files:QFILEIML]]&lt;br /&gt;
* [[CISC AS/400 LIC Tapes]]&lt;br /&gt;
&lt;br /&gt;
== Footnotes ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category: System Internals]]&lt;/div&gt;</summary>
		<author><name>Friedkiwi</name></author>
	</entry>
</feed>