Analysis of Seagate LOD firmware image fileSeagate's
F3 drives (since 7200.11) incorporate modular code in serial flash memory (aka "ROM"). The ROM contains program code plus "adaptive" data modules which are unique to each drive. Whereas previous models updated the ROM as a complete unit, current models update only the code sections. The update may also address certain firmware modules in the System Area (SA) on the platters.
The following tutorial examines the
SD1A2D.LOD file in the
MooseDT-SD1A-2D-8-16-32MB.iso package that was discussed in the following post:
Analysis of Seagate F3 Firmware Update:
viewtopic.php?t=28250&p=194229#p194229The LOD image is comprised of several blocks of code separated by headers. Each header has a size of 64 bytes (= 0x40). Forum member Moltke has written a ZOC script that parses the LOD file and extracts each of these headers (see attachment).
Here is/was the
ZOC script:
http://malthus.zapto.org/viewtopic.php? ... 3162#p3162http://malthus.zapto.org/viewtopic.php? ... 3273#p3273http://malthus.zapto.org/download/file.php?id=602Code:
/* REXX */
cls
DIR_PART="C:\_DUMPS"
MAIN:
TASK=ZocRequestList("SELECT: ","ST_SUMM","LOD_STRUCT")
if TASK= -1 then exit
if TASK= 1 then signal ST_LOD
ST_SUMM:
call GET_FILE ,MAIN
NUM=GETSUMM(abst)
say IN_FILE||" SUMM: "||c2x(NUM)||"h"
SIGNAL MAIN
ST_LOD:
call GET_FILE "SELECT SEAGATE LOD FILE:",MAIN
CURRENT_OFFSET=1 ; LEN_BLOCK=x2d(40)
if c2d(substr(abst,x2d(0E)+1,1))<>7 then do
UNKNFRMT: say "UNKNOWN LOD FORMAT"
signal ST_LOD
end
else do
BLOCK=substr(abst,CURRENT_OFFSET,LEN_BLOCK)
NUM=GETSUMM(BLOCK)
if NUM<>substr(BLOCK,x2d(3E)+1,2) then signal UNKNFRMT
end
LOG_FILE=F_CREATE(DIR_PART,"LOD_HEADERS.TXT") ; t1=time(S)
do while CURRENT_OFFSET<length(abst)
BLOCK=substr(abst,CURRENT_OFFSET,LEN_BLOCK)
call TO_FILE "LOD_"||d2x(CURRENT_OFFSET-1,OFFS_FORMAT)||".BIN",BLOCK
call DO_HEX BLOCK,CURRENT_OFFSET-1,LOG_FILE
NEXT_ADDR=c2d(reverse(substr(BLOCK,x2d(10)+1,4)))
CURRENT_OFFSET=CURRENT_OFFSET+LEN_BLOCK+NEXT_ADDR
end
call stream LOG_FILE,"C","CLOSE"
say "SAVED TO:"
say LOG_FILE||" in "||abs(time(S)-t1)||" sec"
SIGNAL MAIN
BYE: exit
/* ============================================================== */
F_CREATE:
PARSE ARG _DIR,_FILE
IF STREAM(_DIR,"C","QUERY EXISTS")="" THEN DO
CALL ZOCSHELL MD _DIR,1
END
_TMP=_DIR||"\"||_FILE
IF STREAM(_TMP,"C","QUERY EXISTS")<>"" THEN DO
CALL ZOCSHELL DEL _TMP,1
END
CALL STREAM _TMP,"C","OPEN WRITE"
RETURN _TMP
/* ============================================================== */
GET_FILE:
parse arg _MSG,_TO
if _TO="" then _TO=MAIN
if _MSG="" then _MSG="SELECT FILE:"
L0: IN_FILE= ZocGetFilename(_MSG, DIR_PART||"\*.*")
if IN_FILE="##CANCEL##" then signal value _TO
if stream(IN_FILE,"C","QUERY EXISTS")="" then do
say "["||IN_FILE||"] NOT FOUND.RETRY"
signal L0
end
abst=charin(IN_FILE,1,chars(IN_FILE))
call stream IN_FILE,"C","CLOSE"
if length(abst)=0 then do
say "LENGTH FILE=0.TRY NEXT FILE."
signal L0
end
OFFS_FORMAT=length(d2x(length(abst)))
if OFFS_FORMAT < 4 then OFFS_FORMAT=4
i=lastpos("\",IN_FILE)
DIR_PART=left(IN_FILE,i-1)
F_PART=substr(IN_FILE,i+1,)
RETURN
/* ============================================================== */
TO_FILE:
parse arg _FNAME,_BUFF
if _BUFF="" then _BUFF=abst
OUT_FILE=F_CREATE(DIR_PART,_FNAME)
call charout OUT_FILE,_BUFF
call stream OUT_FILE,"C","CLOSE"
say ""
say "SAVED TO:"
say OUT_FILE
RETURN
/* ============================================================== */
FLUSH:
PARSE ARG _FILE,V2
if _FILE="" then _FILE=OUT_FILE
SAY V2
CALL CHAROUT _FILE,V2||X2C(0D0A)
RETURN
/* ============================================================== */
GETSUMM:
parse arg BUFF
LEN_BUFF=length(BUFF) ; SUMM=0
do i=1 to LEN_BUFF by 2
_word=reverse(substr(BUFF,i,2))
SUMM=SUMM+c2d(_word)
if SUMM>=65536 then SUMM=SUMM-65536
end
if SUMM=0 then SUMM=c2d(_word)
else SUMM=65536-SUMM
RETURN reverse(d2c(SUMM))
/* ============================================================== */
DO_HEX:
PARSE ARG _BUFF,_OFFS,F_DUMP
LB=length(_BUFF)
DIGITS_FOR_OFFSET=length(d2x(_OFFS+LB))
if DIGITS_FOR_OFFSET < 4 then DIGITS_FOR_OFFSET=4
_STR="ADDR:|"
IF DIGITS_FOR_OFFSET>4 THEN _STR=COPIES(" ",DIGITS_FOR_OFFSET-4)||_STR
DO K=0 TO 15
_STR=_STR||D2X(K,02)||"|"
END
BORD1=copies("-",length(_STR))
CALL FLUSH F_DUMP,BORD1
CALL FLUSH F_DUMP,_STR
CALL FLUSH F_DUMP,BORD1
do k=1 to LB
if (k-1)//16=0 then do
BINTOHEX=d2x((k-1)+_OFFS,DIGITS_FOR_OFFSET)||":"
BINTOASC=""
end
CHAR=substr(_BUFF,k,1)
BINTOHEX=BINTOHEX||" "||c2x(CHAR)
if c2d(CHAR)<32 | c2d(CHAR)>127 then CHAR=x2c(2E)
BINTOASC=BINTOASC||CHAR
if k//16=0 then CALL FLUSH F_DUMP,BINTOHEX||copies(" ",3)||BINTOASC
end
REST=16-length(BINTOASC)
if REST<>0 then do
BINTOHEX=BINTOHEX||copies(" ",REST*2)
CALL FLUSH F_DUMP,BINTOHEX||copies(" ",3)||BINTOASC
end
CALL FLUSH F_DUMP,""
RETURN
Here is a header example (
LOD_18988.BIN):
Code:
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 17 06 03 13 01 00 00 00 80 27 00 00 00 00 42 04 ........?'....B.
00000010 38 16 06 00 0D 60 02 00 22 01 50 15 01 22 09 20 8....`..".P..".
00000020 08 00 00 00 78 16 06 00 00 00 00 00 00 00 00 00 ....x...........
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D4 D5 ..............OO
The header is located at offset
0x18988 within the LOD file. It has a size of
0x40 bytes.
Offset 0x10 within the header specifies the size of the block of code that follows, namely
0x61638. Therefore this block of code occupies the range 189C8-79FFF (0x189C8 = 0x18988 + 0x40).
Proceeding in this manner, we are able to extract the following 10 code blocks:
Code:
Range Size (hex / decimal)
---------------------------------------
1 00200-021FF 2000 8,192
2 02400-153FF 13000 77,824
3 15500-165FF 1100 4,352
4 16800-187FF 2000 8,192
5 189C8-79FFF 61638 398,904
6 7A040-85DFF BDC0 48,576
7 86000-B5FFF 30000 196,608
8 B6200-D61FF 20000 131,072
9 D6400-E63FF 10000 65,536
10 E6600-F65FF 10000 65,536
In order to identify each of these modules, I compared them against an actual resource dump for an ST3500320AS model with SD1A firmware:
http://files.hddguru.com/download/Non-P ... 20SD1A.rarCode block #5 (
189C8-79FFF) is the first part of the ROM (
CP15.CP in the SD1A resource dump).
Here is the header section of the ROM:
Code:
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 A7 25 00 00 40 00 00 00 40 82 00 00 0D 2C 04 00
00000010 02 38 00 00 04 38 16 06 06 48 18 06 03 58 9C 06
00000020 0B 58 CC 07 05 58 DD 07 0E 70 FD 07 00 00 00 08
Offsets
0x10 -
0x2F define the various code and data modules within the ROM.
Code:
----------------------------
ID start size (hex / dec)
----------------------------
02 000038 61600 398848
04 061638 00210 528
06 061848 08410 33808
03 069C58 13000 77824
0B 07CC58 01100 4352
05 07DD58 02018 8216
0E 07FD70 00290 656
00 080000
After comparing the code blocks against the SD1A resource dump, it is evident that the update modifies 3 sections of the ROM, plus at least 3 firmware modules in the SA, namely MODs
1D,
1E, and
34. There are 2 code blocks which I couldn't match against any resource, so I have no idea where they go. One of them contains ConGen text strings, but strangely the resource dump contains no such text.
02400-153FF = ROM module 03
15500-165FF = ROM module 0B
189C8-79FFF = first part of ROM
7A040-85DFF = SA module 34
86000-B5FFF ---- contains Congen text strings
B6200-D61FF ---- header similar to MODs 1D / 1E , probably MOD 1F
D6400-E63FF = SA module 1E
E6600-F65FF = SA module 1D
The following blocks of code are identical:
Code:
00200-021FF.bin 8,192
16800-187FF.bin 8,192
They do not appear to be firmware modules. Instead they appear to be some kind of firmware loader, perhaps for ROM flashing. In fact I have extracted identical code blocks from Seagate's
Savvio10K5-Compass-SAS-StdOEM-0004 and
Dell's CS09 SAS firmware updates.
I suspect that the code block at
86000-B5FFF might be SA module
1F, but I can't understand why it doesn't show up in the resource dump. Perhaps the dump is from an earlier SD1A package version?
The above modules have the following functions:
1D --- Physical Overlay File 0
1E --- Physical Overlay File 1
1F --- Physical Overlay File 2
34 --- Packed CONGEN XML definition
Module 34 appears to contain ConGen stuff in compressed form.
References:
ZOC (Terminal Emulator, Telnet Client, SSH/SSH2 Client):
http://www.emtec.com/download.html#zocfilesOriginal article:
http://malthus.zapto.org/viewtopic.php? ... 3166#p3166