Skip to content

Commit 7da5a75

Browse files
committed
First version of ASpeed support. Tested on SMT_X10_142.bin only.
1 parent 97e3299 commit 7da5a75

File tree

4 files changed

+146
-72
lines changed

4 files changed

+146
-72
lines changed

ipmifw/ASpeed.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,34 @@ def parse(self, extract, config):
3333
else:
3434
print "Image checksum matches"
3535

36-
37-
config.set('images', str(imagenum), 'present')
38-
configkey = 'image_%i' % imagenum
39-
config.add_section(configkey)
40-
config.set(configkey, 'name', filename)
41-
config.set(configkey, 'base_addr', hex(imagestart))
42-
config.set(configkey, 'length', hex(length))
36+
config.set('images', str(imagenum), 'present')
37+
configkey = 'image_%i' % imagenum
38+
config.add_section(configkey)
39+
config.set(configkey, 'name', filename)
40+
config.set(configkey, 'base_addr', hex(imagestart))
41+
config.set(configkey, 'length', hex(length))
4342
config.set(configkey, 'checksum', hex(checksum))
4443

45-
4644
imagenum += 1
4745

4846
# Next, find and validate the global footer
4947
for imageFooter in re.findall("ATENs_FW(.{20})",self.ipmifw,re.DOTALL):
5048

51-
(rev1, rev2, unknown) = struct.unpack("<bb18s", imageFooter)
52-
print "footer: %x.%x unknown: %s" % (rev1, rev2, unknown)
53-
#print "\n"+str(footer)
54-
55-
#if footer.checksum == computed_checksum:
56-
# print "Firmware checksum matches"
57-
#else:
58-
# print "Firwamre checksum mismatch, footer: 0x%x computed: 0x%x" % (footer.checksum, computed_checksum)
49+
(rev1, rev2, rootfs_crc, rootfs_len, fwtag1, webfs_crc, webfs_len, fwtag2) = struct.unpack("<bb4s4sb4s4sb", imageFooter)
50+
if fwtag1 != 0x71 or fwtag2 != 0x17:
51+
print "Error matching footer tags"
52+
else:
53+
len2 = config.get('image_2', 'length')
54+
crc2 = config.get('image_2', 'checksum')
55+
len4 = config.get('image_4', 'length')
56+
crc4 = config.get('image_4', 'checksum')
57+
if rootfs_len != len2[2:6] or rootfs_crc != crc2[2:6]:
58+
print "Root_fs image info does not match"
59+
elif webfs_len != len4[2:6] or webfs_crc != crc4[2:6]:
60+
print "Web_fs image info does not match"
61+
else:
62+
print "Footer OK, rev: %x.%x" % (rev1, rev2)
5963

6064
config.set('global', 'major_version', rev1)
6165
config.set('global', 'minor_version', rev2)
62-
#config.set('global', 'footer_version', footer.footerver)
6366

ipmifw/FirmwareFooter.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,47 @@ class FirmwareFooter:
77
# Footer version 2:
88
# ATENs_FW MAJORVER MINORVER 0x71 CHECKSUM 0x17
99

10+
# Footer version 3:
11+
# ATENs_FW MAJORVER MINORVER ROOTFS_NFO 0x71 WEBFS_NFO 0x17
12+
1013
def __init__(self):
1114
# these together get you the firmware version: rev1.rev2
1215
self.rev1 = 0
1316
self.rev2 = 0
1417
self.checksum = 0
18+
self.rootfs_nfo = 0
19+
self.webfs_nfo = 0
1520
# fwtag appears to be some way of recogizing that this is indeed a footer
1621
# should be 0x71
1722
self.fwtag1 = 0x71
1823
# should be 0x17
1924
self.fwtag2 = 0x17
20-
self.footerver = 2
25+
self.footerver = 3
2126

2227
def loadFromString(self, footer):
23-
(self.rev1, self.rev2, self.fwtag1, self.checksum, self.fwtag2) = struct.unpack("<bbbIb", footer)
24-
# Seems firmware older then v3.00 uses a different footer, which doesn't have the tag
28+
(self.rev1, self.rev2, self.rootfs_nfo, self.fwtag1, self.webfs_nfo, self.fwtag2) = struct.unpack("<bb8sb8sb", footer)
29+
# Older footer versions have tags at different offset
2530
if self.fwtag1 != 0x71 or self.fwtag2 != 0x17:
26-
(self.rev1, self.rev2, self.checksum) = struct.unpack("<bbI", footer[:6])
27-
self.footerver = 1
28-
self.fwtag1 = 0
29-
self.fwtag2 = 0
31+
self.footerver = 2
32+
(self.rev1, self.rev2, self.fwtag1, self.checksum, self.fwtag2) = struct.unpack("<bbbIb", footer)
33+
# Seems firmware older then v3.00 uses a different footer, which doesn't have the tag
34+
if self.fwtag1 != 0x71 or self.fwtag2 != 0x17:
35+
(self.rev1, self.rev2, self.checksum) = struct.unpack("<bbI", footer[:6])
36+
self.footerver = 1
37+
self.fwtag1 = 0
38+
self.fwtag2 = 0
3039

3140
def getRawString(self):
32-
if self.footerver == 2:
41+
if self.footerver == 3:
42+
contents = "ATENs_FW"+struct.pack("<bb8sb8sb", self.rev1, self.rev2, self.rootfs_nfo, self.fwtag1, self.webfs_nfo, self.fwtag2)
43+
elif self.footerver == 2:
3344
contents = "ATENs_FW"+struct.pack("<bbbIb", self.rev1, self.rev2, self.fwtag1, self.checksum, self.fwtag2)
3445
else:
3546
contents = "ATENs_FW"+struct.pack("<bbI", self.rev1, self.rev2, self.checksum)
3647
return contents
3748

3849
def __str__(self):
39-
return "Firmware footer version %i firmware version %i.%i checksum: 0x%x tag: 0x%x%x" % (self.footerver, self.rev1, self.rev2, self.checksum, self.fwtag1, self.fwtag2)
50+
return "Firmware footer version %i firmware version %i.%i checksum: 0x%x tag: 0x%x%x rootfs_nfo: 0x%s webfs_nfo: 0x%s" % (self.footerver, self.rev1, self.rev2, self.checksum, self.fwtag1, self.fwtag2, self.rootfs_nfo, self.webfs_nfo)
4051

4152
def computeFooterChecksum(self, imagecrc):
4253
rawCRCBuf = ""

read_header.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/local/bin/python2.7
1+
#!/usr/bin/python
22

33
import re, hashlib, os, io, argparse, sys, zlib
44
from ConfigParser import ConfigParser
@@ -70,6 +70,7 @@
7070
elif fwtype == 'aspeed':
7171
from ipmifw.ASpeed import ASpeed
7272

73+
config.set('global', 'footer_version', 3)
7374
firmware = ASpeed(ipmifw)
7475
firmware.parse(args.extract, config)
7576

rebuild_image.py

Lines changed: 104 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/local/bin/python2.7
1+
#!/usr/bin/python
22

33
import os, io, sys, math, zlib
44
from ConfigParser import ConfigParser
@@ -15,14 +15,36 @@
1515
new_image = open('data/rebuilt_image.bin','w')
1616
new_image.truncate()
1717

18-
for i in range(0,config.getint('flash','total_size')):
19-
new_image.write("\xFF")
18+
if config.get('global','type') == 'aspeed':
19+
aspeed = True
20+
else:
21+
aspeed = False
22+
23+
total_size = config.getint('flash','total_size')
24+
if not aspeed:
25+
for i in range(0,total_size):
26+
new_image.write('\xFF')
27+
else:
28+
# Apseed image has some parts filled with nulls
29+
# it probably does not matter, but let's try make identical image
30+
if total_size < 0x1F40000:
31+
print "Unexpected ASpeed image size"
32+
os.exit(1)
33+
for i in range(0,0x100000):
34+
new_image.write('\xFF')
35+
for i in range(0x100000,0x400000):
36+
new_image.write('\x00')
37+
for i in range(0x400000,0x1F40000):
38+
new_image.write('\xFF')
39+
for i in range(0x1F40000,total_size):
40+
new_image.write('\x00')
2041

2142
new_image.seek(0)
2243

23-
print "Writing bootloader..."
24-
with open('data/bootloader.bin','r') as f:
25-
new_image.write(f.read())
44+
if not aspeed:
45+
print "Writing bootloader..."
46+
with open('data/bootloader.bin','r') as f:
47+
new_image.write(f.read())
2648

2749
images = []
2850
for (imagenum, dummy) in config.items('images'):
@@ -39,15 +61,16 @@
3961
# can't use getint, it doesn't support hex
4062
old_length = int(config.get(configkey, 'length'),0)
4163
base_addr = int(config.get(configkey, 'base_addr'),0)
42-
load_addr = int(config.get(configkey, 'load_addr'),0)
43-
exec_addr = int(config.get(configkey, 'exec_addr'),0)
64+
if not aspeed:
65+
load_addr = int(config.get(configkey, 'load_addr'),0)
66+
exec_addr = int(config.get(configkey, 'exec_addr'),0)
67+
type = int(config.get(configkey, 'type'),0)
4468
name = config.get(configkey, 'name')
45-
type = int(config.get(configkey, 'type'),0)
4669

47-
imagestart = base_addr
48-
if imagestart > 0x40000000:
49-
# I'm unsure where this 0x40000000 byte offset is coming from. Perhaps I'm not parsing the footer correctly?
50-
imagestart -= 0x40000000
70+
imagestart = base_addr
71+
if imagestart > 0x40000000:
72+
# I'm unsure where this 0x40000000 byte offset is coming from. Perhaps I'm not parsing the footer correctly?
73+
imagestart -= 0x40000000
5174

5275
if imagestart < new_image.tell():
5376
print "ERROR: Previous image was too big, and has overriten data where the current image should begin."
@@ -57,7 +80,9 @@
5780
# Seek to where this image will start
5881
new_image.seek(imagestart)
5982

60-
with open('data/%s.bin' % name,'r') as img:
83+
if name[-4:] != '.bin':
84+
name = name + '.bin'
85+
with open('data/%s' % name,'r') as img:
6186
cur_image = img.read()
6287

6388
# Write the actual image contents
@@ -67,57 +92,91 @@
6792
curcrc = zlib.crc32(cur_image) & 0xffffffff
6893
imagecrc.append(curcrc)
6994

70-
# Prepare the image footer based on the data we've stored previously
71-
fi = FirmwareImage()
72-
fi.imagenum = imagenum
73-
fi.base_address = base_addr
74-
fi.exec_address = exec_addr
75-
fi.load_address = load_addr
76-
fi.name = name
77-
fi.image_checksum = FirmwareImage.computeChecksum(cur_image)
78-
fi.type = type
79-
fi.length = len(cur_image)
95+
config.set(configkey, 'curcrc', '0x%x' % curcrc)
96+
config.set(configkey, 'curlen', '0x%x' % len(cur_image))
8097

81-
# Calculate the new checksum..
82-
fi.footer_checksum = fi.computeFooterChecksum()
98+
if not aspeed:
99+
# Prepare the image footer based on the data we've stored previously
100+
fi = FirmwareImage()
101+
fi.imagenum = imagenum
102+
fi.base_address = base_addr
103+
fi.exec_address = exec_addr
104+
fi.load_address = load_addr
105+
fi.type = type
106+
fi.name = name
107+
fi.image_checksum = FirmwareImage.computeChecksum(cur_image)
108+
fi.length = len(cur_image)
83109

84-
# flash chip breaks data down into 64KB blocks. Footer should be at the end of one of these
85-
curblock = int(math.floor(new_image.tell() / 65536))
110+
# Calculate the new checksum..
111+
fi.footer_checksum = fi.computeFooterChecksum()
86112

87-
curblockend = curblock * 65536
113+
# flash chip breaks data down into 64KB blocks. Footer should be at the end of one of these
114+
curblock = int(math.floor(new_image.tell() / 65536))
88115

89-
last_image_end = new_image.tell()
116+
curblockend = curblock * 65536
90117

91-
# If we don't have space to write the footer at the end of the current block, move to the next block
92-
if curblockend - 61 < last_image_end:
93-
curblock += 1
118+
last_image_end = new_image.tell()
94119

95-
footerpos = (curblock * 65536) - 61
120+
# If we don't have space to write the footer at the end of the current block, move to the next block
121+
if curblockend - 61 < last_image_end:
122+
curblock += 1
96123

97-
new_image.seek(footerpos)
124+
footerpos = (curblock * 65536) - 61
98125

99-
# And write the footer to the output file
100-
new_image.write(fi.getRawString())
126+
new_image.seek(footerpos)
101127

128+
# And write the footer to the output file
129+
new_image.write(fi.getRawString())
130+
131+
else:
132+
footerpos = new_image.tell()
133+
if curcrc == int(config.get(configkey, 'checksum'), 0):
134+
print " Image unchanged"
135+
else:
136+
print " Image modified"
102137

103138
footer = FirmwareFooter()
104139
footer.rev1 = int(config.get('global','major_version'),0)
105140
footer.rev2 = int(config.get('global','minor_version'),0)
106141
footer.footerver = int(config.get('global','footer_version'),0)
107142
footer.checksum = footer.computeFooterChecksum(imagecrc)
108143

109-
# Hmm... no documentation on where this should be, but in the firmware I have it's been palced right before the last image footer
110-
# Unsure if that's where it goes, or if it doesn't matter
111-
# 16 includes 8 padding \xFF's between the global footer and the last image footer
112-
global_start = footerpos-16
113-
if global_start < curblockend:
114-
print "ERROR: Would have written global footer over last image"
115-
print "Aborting"
116-
sys.exit(1)
144+
if not aspeed:
145+
# Hmm... no documentation on where this should be, but in the firmware I have it's been palced right before the last image footer
146+
# Unsure if that's where it goes, or if it doesn't matter
147+
# 16 includes 8 padding \xFF's between the global footer and the last image footer
148+
global_start = footerpos-16
149+
if global_start < curblockend:
150+
print "ERROR: Would have written global footer over last image"
151+
print "Aborting"
152+
sys.exit(1)
153+
else:
154+
# ASpeed seems to place global footer right after the last image
155+
global_start = footerpos - 10
156+
crc2 = config.get('image_2', 'curcrc')
157+
len2 = config.get('image_2', 'curlen')
158+
crc4 = config.get('image_4', 'curcrc')
159+
len4 = config.get('image_4', 'curlen')
160+
footer.rootfs_nfo = '%4s%4s' % (crc2[2:6], len2[2:6])
161+
footer.webfs_nfo = '%4s%4s' % (crc4[2:6], len4[2:6])
117162

118163
# Write the global footer
119164
new_image.seek(global_start)
120165
new_image.write(footer.getRawString())
121166

167+
# add ASpeed specific index
168+
if aspeed:
169+
new_image.seek(0x1FC0000)
170+
for imagenum in images:
171+
configkey = 'image_%i' % imagenum
172+
img_base = int(config.get(configkey, 'base_addr'),0)
173+
img_len = int(config.get(configkey, 'curlen'),0)
174+
img_crc = int(config.get(configkey, 'curcrc'),0)
175+
img_name = config.get(configkey, 'name')
176+
177+
new_image.write("[img]: ")
178+
new_image.write("%x %x %x %s" % (img_base, img_len, img_crc, img_name))
179+
new_image.write("[end]")
180+
122181
print "Done, new firmware written to data/rebuild_image.bin"
123182

0 commit comments

Comments
 (0)