blob: 2d763ca9ddc9363568a3199df81ae213a6dbb481 [file] [log] [blame]
Vishal Bhoj9a67d912016-06-09 10:02:07 +01001#!/usr/bin/env python
2
3import os
4import os.path
5import sys, getopt
6import binascii
7import struct
8import string
9
10class generator(object):
11 #
12 # struct l_loader_head {
13 # unsigned int first_instr;
14 # unsigned char magic[16]; @ BOOTMAGICNUMBER!
15 # unsigned int l_loader_start;
16 # unsigned int l_loader_end;
17 # };
18 file_header = [0, 0, 0, 0, 0, 0, 0]
19
20 #
21 # struct entry_head {
22 # unsigned char magic[8]; @ ENTY
23 # unsigned char name[8]; @ loader/bl1
24 # unsigned int start_lba;
25 # unsigned int count_lba;
26 # unsigned int flag; @ boot partition or not
27 # };
28
29 s1_entry_name = ['loader', 'bl1']
30 s2_entry_name = ['primary', 'second']
31
32 block_size = 512
33
34 stage = 0
35
36 # set in self.add()
37 idx = 0
38
39 # set in self.parse()
40 ptable_lba = 0
41 stable_lba = 0
42
43 # file pointer
44 p_entry = 0
45 p_file = 0
46
47 def __init__(self, out_img):
48 try:
49 self.fp = open(out_img, "wb+")
50 except IOError, e:
51 print "*** file open error:", e
52 sys.exit(3)
53 else:
54 self.entry_hd = [[0 for col in range(7)] for row in range(5)]
55
56 def __del__(self):
57 self.fp.close()
58
59 # parse partition from the primary ptable
60 def parse(self, fname):
61 try:
62 fptable = open(fname, "rb")
63 except IOError, e:
64 print "*** file open error:", e
65 sys.exit(3)
66 else:
67 # skip the first block in primary partition table
68 # that is MBR protection information
69 fptable.read(self.block_size)
70 # check whether it's a primary paritition table
71 data = struct.unpack("8s", fptable.read(8))
72 efi_magic = 'EFI PART'
73 if cmp("EFI PART", data[0]):
74 print "It's not partition table image."
75 fptable.close()
76 sys.exit(4)
77 # skip 16 bytes
78 fptable.read(16)
79 # get lba of both primary partition table and secondary partition table
80 data = struct.unpack("QQQQ", fptable.read(32))
81 self.ptable_lba = data[0] - 1
82 self.stable_lba = data[3] + 1
83 # skip 24 bytes
84 fptable.read(24)
85 data = struct.unpack("i", fptable.read(4))
86 pentries = data[0]
87 # skip the reset in this block
88 fptable.read(self.block_size - 84)
89
90 for i in range(1, pentries):
91 # name is encoded as UTF-16
92 d0,lba,d2,name = struct.unpack("32sQ16s72s", fptable.read(128))
93 plainname = unicode(name, "utf-16")
94 if (not cmp(plainname[0:7], 'l-loader'[0:7])):
95 print 'bl1_lba: ', lba
96 self.bl1_lba = lba
97 sys.exit(1)
98
99 fptable.close()
100
101 def add(self, lba, fname):
102 try:
103 fsize = os.path.getsize(fname)
104 except IOError, e:
105 print "*** file open error:", e
106 sys.exit(4)
107 else:
108 blocks = (fsize + self.block_size - 1) / self.block_size
109 if (self.stage == 1):
110 # Boot Area1 in eMMC
111 bootp = 1
112 if self.idx == 0:
113 self.p_entry = 28
114 elif (self.stage == 2):
115 # User Data Area in eMMC
116 bootp = 0
117 # create an empty block only for stage2
118 # This empty block is used to store entry head
119 print 'p_file: ', self.p_file, 'p_entry: ', self.p_entry
120 if self.idx == 0:
121 self.fp.seek(self.p_file)
122 for i in range (0, self.block_size):
123 zero = struct.pack('x')
124 self.fp.write(zero)
125 self.p_file += self.block_size
126 self.p_entry = 0
127 else:
128 print "wrong stage ", stage, "is specified"
129 sys.exit(4)
130 # Maybe the file size isn't aligned. So pad it.
131 if (self.idx == 0) and (self.stage == 1):
132 if fsize > 2048:
133 print 'loader size exceeds 2KB. file size: ', fsize
134 sys.exit(4)
135 else:
136 left_bytes = 2048 - fsize
137 else:
138 left_bytes = fsize % self.block_size
139 if left_bytes:
140 left_bytes = self.block_size - left_bytes
141 print 'lba: ', lba, 'blocks: ', blocks, 'bootp: ', bootp, 'fname: ', fname
142 # write images
143 fimg = open(fname, "rb")
144 for i in range (0, blocks):
145 buf = fimg.read(self.block_size)
146 self.fp.seek(self.p_file)
147 self.fp.write(buf)
148 # p_file is the file pointer of the new binary file
149 # At last, it means the total block size of the new binary file
150 self.p_file += self.block_size
151
152 if (self.idx == 0) and (self.stage == 1):
153 self.p_file = 2048
154 print 'p_file: ', self.p_file, 'last block is ', fsize % self.block_size, 'bytes', ' tell: ', self.fp.tell(), 'left_bytes: ', left_bytes
155 if left_bytes:
156 for i in range (0, left_bytes):
157 zero = struct.pack('x')
158 self.fp.write(zero)
159 print 'p_file: ', self.p_file, ' pad to: ', self.fp.tell()
160
161 # write entry information at the header
162 if self.stage == 1:
163 byte = struct.pack('8s8siii', 'ENTRYHDR', self.s1_entry_name[self.idx], lba, blocks, bootp)
164 elif self.stage == 2:
165 byte = struct.pack('8s8siii', 'ENTRYHDR', self.s2_entry_name[self.idx], lba, blocks, bootp)
166 self.fp.seek(self.p_entry)
167 self.fp.write(byte)
168 self.p_entry += 28
169 self.idx += 1
170
171 fimg.close()
172
173 def hex2(self, data):
174 return data > 0 and hex(data) or hex(data & 0xffffffff)
175
176 def end(self):
177 if self.stage == 1:
178 self.fp.seek(20)
179 start,end = struct.unpack("ii", self.fp.read(8))
180 print "start: ", self.hex2(start), 'end: ', self.hex2(end)
181 end = start + self.p_file
182 print "start: ", self.hex2(start), 'end: ', self.hex2(end)
183 self.fp.seek(24)
184 byte = struct.pack('i', end)
185 self.fp.write(byte)
186 self.fp.close()
187
188 def create_stage1(self, img_loader, img_bl1, output_img):
189 print '+-----------------------------------------------------------+'
190 print ' Input Images:'
191 print ' loader: ', img_loader
192 print ' bl1: ', img_bl1
193 print ' Ouput Image: ', output_img
194 print '+-----------------------------------------------------------+\n'
195
196 self.stage = 1
197
198 # The first 2KB is reserved
199 # The next 2KB is for loader image
200 self.add(4, img_loader) # img_loader doesn't exist in partition table
201 print 'self.idx: ', self.idx
202 # bl1.bin starts from 4KB
203 self.add(8, img_bl1) # img_bl1 doesn't exist in partition table
204
205 def create_stage2(self, img_prm_ptable, img_sec_ptable, output_img):
206 print '+-----------------------------------------------------------+'
207 print ' Input Images:'
208 print ' primary partition table: ', img_prm_ptable
209 print ' secondary partition table: ', img_sec_ptable
210 print ' Ouput Image: ', output_img
211 print '+-----------------------------------------------------------+\n'
212
213 self.stage = 2
214 self.parse(img_prm_ptable)
215 self.add(self.ptable_lba, img_prm_ptable)
216 if (cmp(img_sec_ptable, 'secondary partition table')):
217 # Doesn't match. It means that secondary ptable is specified.
218 self.add(self.stable_lba, img_sec_ptable)
219 else:
220 print 'Don\'t need secondary partition table'
221
222def main(argv):
223 stage1 = 0
224 stage2 = 0
225 img_prm_ptable = "primary partition table"
226 img_sec_ptable = "secondary partition table"
227 try:
228 opts, args = getopt.getopt(argv,"ho:",["img_loader=","img_bl1=","img_prm_ptable=","img_sec_ptable="])
229 except getopt.GetoptError:
230 print 'gen_loader.py -o <l-loader.bin> --img_loader <l-loader> --img_bl1 <bl1.bin> --img_prm_ptable <prm_ptable.img> --img_sec_ptable <sec_ptable.img>'
231 sys.exit(2)
232 for opt, arg in opts:
233 if opt == '-h':
234 print 'gen_loader.py -o <l-loader.bin> --img_loader <l-loader> --img_bl1 <bl1.bin> --img_prm_ptable <prm_ptable.img> --img_sec_ptable <sec_ptable.img>'
235 sys.exit(1)
236 elif opt == '-o':
237 output_img = arg
238 elif opt in ("--img_loader"):
239 img_loader = arg
240 stage1 = 1
241 elif opt in ("--img_bl1"):
242 img_bl1 = arg
243 stage1 = 1
244 elif opt in ("--img_prm_ptable"):
245 img_prm_ptable = arg
246 stage2 = 1
247 elif opt in ("--img_sec_ptable"):
248 img_sec_ptable = arg
249
250 loader = generator(output_img)
251 loader.idx = 0
252
253 if (stage1 == 1) and (stage2 == 1):
254 print 'There are only loader & BL1 in stage1.'
255 print 'And there are primary partition table, secondary partition table and FIP in stage2.'
256 sys.exit(1)
257 elif (stage1 == 0) and (stage2 == 0):
258 print 'No input images are specified.'
259 sys.exit(1)
260 elif stage1 == 1:
261 loader.create_stage1(img_loader, img_bl1, output_img)
262 elif stage2 == 1:
263 loader.create_stage2(img_prm_ptable, img_sec_ptable, output_img)
264
265 loader.end()
266
267if __name__ == "__main__":
268 main(sys.argv[1:])