blob: 3d5adf501a1c6bc2ea1abce71c7f30774ef5d6cc [file] [log] [blame]
Denis 'GNUtoo' Carikli40a2a9c2017-03-01 14:56:25 +01001#!/usr/bin/env python2
roxfan38217fa2013-01-15 14:33:34 +01002# Dell/Phoenix ROM BIOS PLUS unpacker
3# 2012-09-12 version 0.1
4# 2012-10-10 version 0.2 added support for older BIOSes with 16-bit length (Dell Inspiron 1100)
5# 3-clause BSD license
6# roxfan@skynet.be
7
8import array
9import struct
10import sys
11
12def memcpy(arr1, off1, arr2, off2, count):
13 while count:
14 if off1 < len(arr1):
15 arr1[off1] = arr2[off2]
16 elif off1 == len(arr1):
17 arr1.append(arr2[off2])
18 else:
19 raise Exception("Trying to write out of bounds")
20 off1 += 1
21 off2 += 1
22 count -=1
23
24# looks like some lzss variation
25def dell_unpack(indata):
26 srcoff = 0
27 dstoff = 0
28 src = array.array('B', indata)
29 dst = array.array('B')
30 inlen = len(indata)
31 while srcoff < inlen:
32 b = src[srcoff]
33 nibl, nibh = b & 0x0F, (b >> 4) & 0x0F
34 srcoff += 1
35 if nibl:
36 if nibl == 0xF:
37 al = src[srcoff]
38 ah = src[srcoff+1]
39 srcoff += 2
40 cx = nibh | (ah << 4)
41 count = (cx & 0x3F) + 2
42 delta = ((ah >> 2) << 8) | al
43 else:
44 count = nibl + 1
45 delta = (nibh << 8) | src[srcoff]
46 srcoff += 1
47 memcpy(dst, dstoff, dst, dstoff - delta - 1, count)
48 dstoff += count
49 elif nibh == 0x0E:
50 count = src[srcoff] + 1
51 srcoff += 1
52 memcpy(dst, dstoff, dst, dstoff - 1, count)
53 dstoff += count
54 else:
55 if nibh == 0x0F:
56 count = src[srcoff] + 15
57 srcoff += 1
58 else:
59 count = nibh + 1
60 memcpy(dst, dstoff, src, srcoff, count)
61 dstoff += count
62 srcoff += count
63
64 return dst.tostring()
65
66mod_types = {
67 0x01: "Main ROM",
68 0x0C: "Microcode update",
69}
70
71print "Dell/Phoenix ROM BIOS PLUS unpacker"
72if len(sys.argv) < 2:
73 print "Usage: dell_unpack.py bios.bin [offset]"
74 sys.exit(1)
75fname = sys.argv[1]
76offs = 0
77f = open(fname, "rb").read()
78if len(sys.argv) > 2:
79 offs = int(sys.argv[2], 16)
80else:
81 offs = f.find("\xF0\x00Copyright 1985-\x02\x04\xF0\x0F8 Phoenix Technologies Ltd.")
82 if offs == -1:
83 print "Does not look like a Dell/Phoenix ROM BIOS PLUS"
84 sys.exit(2)
85 if f[offs-5] == '\x01':
86 hlen = 5 # 32-bit length
87 offs -= 5
88 fmt = "<BI"
89 elif f[offs-3] == '\x01':
90 hlen = 3 # 16-bit length
91 offs -= 3
92 fmt = "<BH"
93 else:
94 print "Unhandled format!"
95 sys.exit(1)
96 print "Found compressed module at %08X" % offs
97if offs > 0:
98 fn = "EC.bin"
99 print "%08X EC code, %08X %s" % (0, offs, fn)
100 open(fn, "wb").write(f[:offs])
101while True:
102 type, leng = struct.unpack(fmt, f[offs:offs+hlen])
103 print "%08X type %02X" % (offs, type),
104 offs += hlen
105 if type == 0xFF:
106 print "<end of chain>"
107 break
108 data = f[offs:offs+leng]
109 offs += leng
110 if type != 0xC:
111 odata = dell_unpack(data)
112 else:
113 odata = data
114 print " %08X -> %08X" % (leng, len(odata)),
115 fn = "mod_%02X.bin" % type
116 print " %s" % fn,
117 if type in mod_types:
118 print "(%s)" % mod_types[type]
119 else:
120 print ""
121 open(fn, "wb").write(odata)