268 lines
9.7 KiB
Python
Executable file
268 lines
9.7 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
import os
|
|
import os.path
|
|
import sys, getopt
|
|
import binascii
|
|
import struct
|
|
import string
|
|
|
|
class generator(object):
|
|
#
|
|
# struct l_loader_head {
|
|
# unsigned int first_instr;
|
|
# unsigned char magic[16]; @ BOOTMAGICNUMBER!
|
|
# unsigned int l_loader_start;
|
|
# unsigned int l_loader_end;
|
|
# };
|
|
file_header = [0, 0, 0, 0, 0, 0, 0]
|
|
|
|
#
|
|
# struct entry_head {
|
|
# unsigned char magic[8]; @ ENTY
|
|
# unsigned char name[8]; @ loader/bl1
|
|
# unsigned int start_lba;
|
|
# unsigned int count_lba;
|
|
# unsigned int flag; @ boot partition or not
|
|
# };
|
|
|
|
s1_entry_name = ['loader', 'bl1']
|
|
s2_entry_name = ['primary', 'second']
|
|
|
|
block_size = 512
|
|
|
|
stage = 0
|
|
|
|
# set in self.add()
|
|
idx = 0
|
|
|
|
# set in self.parse()
|
|
ptable_lba = 0
|
|
stable_lba = 0
|
|
|
|
# file pointer
|
|
p_entry = 0
|
|
p_file = 0
|
|
|
|
def __init__(self, out_img):
|
|
try:
|
|
self.fp = open(out_img, "wb+")
|
|
except IOError, e:
|
|
print "*** file open error:", e
|
|
sys.exit(3)
|
|
else:
|
|
self.entry_hd = [[0 for col in range(7)] for row in range(5)]
|
|
|
|
def __del__(self):
|
|
self.fp.close()
|
|
|
|
# parse partition from the primary ptable
|
|
def parse(self, fname):
|
|
try:
|
|
fptable = open(fname, "rb")
|
|
except IOError, e:
|
|
print "*** file open error:", e
|
|
sys.exit(3)
|
|
else:
|
|
# skip the first block in primary partition table
|
|
# that is MBR protection information
|
|
fptable.read(self.block_size)
|
|
# check whether it's a primary paritition table
|
|
data = struct.unpack("8s", fptable.read(8))
|
|
efi_magic = 'EFI PART'
|
|
if cmp("EFI PART", data[0]):
|
|
print "It's not partition table image."
|
|
fptable.close()
|
|
sys.exit(4)
|
|
# skip 16 bytes
|
|
fptable.read(16)
|
|
# get lba of both primary partition table and secondary partition table
|
|
data = struct.unpack("QQQQ", fptable.read(32))
|
|
self.ptable_lba = data[0] - 1
|
|
self.stable_lba = data[3] + 1
|
|
# skip 24 bytes
|
|
fptable.read(24)
|
|
data = struct.unpack("i", fptable.read(4))
|
|
pentries = data[0]
|
|
# skip the reset in this block
|
|
fptable.read(self.block_size - 84)
|
|
|
|
for i in range(1, pentries):
|
|
# name is encoded as UTF-16
|
|
d0,lba,d2,name = struct.unpack("32sQ16s72s", fptable.read(128))
|
|
plainname = unicode(name, "utf-16")
|
|
if (not cmp(plainname[0:7], 'l-loader'[0:7])):
|
|
print 'bl1_lba: ', lba
|
|
self.bl1_lba = lba
|
|
sys.exit(1)
|
|
|
|
fptable.close()
|
|
|
|
def add(self, lba, fname):
|
|
try:
|
|
fsize = os.path.getsize(fname)
|
|
except IOError, e:
|
|
print "*** file open error:", e
|
|
sys.exit(4)
|
|
else:
|
|
blocks = (fsize + self.block_size - 1) / self.block_size
|
|
if (self.stage == 1):
|
|
# Boot Area1 in eMMC
|
|
bootp = 1
|
|
if self.idx == 0:
|
|
self.p_entry = 28
|
|
elif (self.stage == 2):
|
|
# User Data Area in eMMC
|
|
bootp = 0
|
|
# create an empty block only for stage2
|
|
# This empty block is used to store entry head
|
|
print 'p_file: ', self.p_file, 'p_entry: ', self.p_entry
|
|
if self.idx == 0:
|
|
self.fp.seek(self.p_file)
|
|
for i in range (0, self.block_size):
|
|
zero = struct.pack('x')
|
|
self.fp.write(zero)
|
|
self.p_file += self.block_size
|
|
self.p_entry = 0
|
|
else:
|
|
print "wrong stage ", stage, "is specified"
|
|
sys.exit(4)
|
|
# Maybe the file size isn't aligned. So pad it.
|
|
if (self.idx == 0) and (self.stage == 1):
|
|
if fsize > 2048:
|
|
print 'loader size exceeds 2KB. file size: ', fsize
|
|
sys.exit(4)
|
|
else:
|
|
left_bytes = 2048 - fsize
|
|
else:
|
|
left_bytes = fsize % self.block_size
|
|
if left_bytes:
|
|
left_bytes = self.block_size - left_bytes
|
|
print 'lba: ', lba, 'blocks: ', blocks, 'bootp: ', bootp, 'fname: ', fname
|
|
# write images
|
|
fimg = open(fname, "rb")
|
|
for i in range (0, blocks):
|
|
buf = fimg.read(self.block_size)
|
|
self.fp.seek(self.p_file)
|
|
self.fp.write(buf)
|
|
# p_file is the file pointer of the new binary file
|
|
# At last, it means the total block size of the new binary file
|
|
self.p_file += self.block_size
|
|
|
|
if (self.idx == 0) and (self.stage == 1):
|
|
self.p_file = 2048
|
|
print 'p_file: ', self.p_file, 'last block is ', fsize % self.block_size, 'bytes', ' tell: ', self.fp.tell(), 'left_bytes: ', left_bytes
|
|
if left_bytes:
|
|
for i in range (0, left_bytes):
|
|
zero = struct.pack('x')
|
|
self.fp.write(zero)
|
|
print 'p_file: ', self.p_file, ' pad to: ', self.fp.tell()
|
|
|
|
# write entry information at the header
|
|
if self.stage == 1:
|
|
byte = struct.pack('8s8siii', 'ENTRYHDR', self.s1_entry_name[self.idx], lba, blocks, bootp)
|
|
elif self.stage == 2:
|
|
byte = struct.pack('8s8siii', 'ENTRYHDR', self.s2_entry_name[self.idx], lba, blocks, bootp)
|
|
self.fp.seek(self.p_entry)
|
|
self.fp.write(byte)
|
|
self.p_entry += 28
|
|
self.idx += 1
|
|
|
|
fimg.close()
|
|
|
|
def hex2(self, data):
|
|
return data > 0 and hex(data) or hex(data & 0xffffffff)
|
|
|
|
def end(self):
|
|
if self.stage == 1:
|
|
self.fp.seek(20)
|
|
start,end = struct.unpack("ii", self.fp.read(8))
|
|
print "start: ", self.hex2(start), 'end: ', self.hex2(end)
|
|
end = start + self.p_file
|
|
print "start: ", self.hex2(start), 'end: ', self.hex2(end)
|
|
self.fp.seek(24)
|
|
byte = struct.pack('i', end)
|
|
self.fp.write(byte)
|
|
self.fp.close()
|
|
|
|
def create_stage1(self, img_loader, img_bl1, output_img):
|
|
print '+-----------------------------------------------------------+'
|
|
print ' Input Images:'
|
|
print ' loader: ', img_loader
|
|
print ' bl1: ', img_bl1
|
|
print ' Ouput Image: ', output_img
|
|
print '+-----------------------------------------------------------+\n'
|
|
|
|
self.stage = 1
|
|
|
|
# The first 2KB is reserved
|
|
# The next 2KB is for loader image
|
|
self.add(4, img_loader) # img_loader doesn't exist in partition table
|
|
print 'self.idx: ', self.idx
|
|
# bl1.bin starts from 4KB
|
|
self.add(8, img_bl1) # img_bl1 doesn't exist in partition table
|
|
|
|
def create_stage2(self, img_prm_ptable, img_sec_ptable, output_img):
|
|
print '+-----------------------------------------------------------+'
|
|
print ' Input Images:'
|
|
print ' primary partition table: ', img_prm_ptable
|
|
print ' secondary partition table: ', img_sec_ptable
|
|
print ' Ouput Image: ', output_img
|
|
print '+-----------------------------------------------------------+\n'
|
|
|
|
self.stage = 2
|
|
self.parse(img_prm_ptable)
|
|
self.add(self.ptable_lba, img_prm_ptable)
|
|
if (cmp(img_sec_ptable, 'secondary partition table')):
|
|
# Doesn't match. It means that secondary ptable is specified.
|
|
self.add(self.stable_lba, img_sec_ptable)
|
|
else:
|
|
print 'Don\'t need secondary partition table'
|
|
|
|
def main(argv):
|
|
stage1 = 0
|
|
stage2 = 0
|
|
img_prm_ptable = "primary partition table"
|
|
img_sec_ptable = "secondary partition table"
|
|
try:
|
|
opts, args = getopt.getopt(argv,"ho:",["img_loader=","img_bl1=","img_prm_ptable=","img_sec_ptable="])
|
|
except getopt.GetoptError:
|
|
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>'
|
|
sys.exit(2)
|
|
for opt, arg in opts:
|
|
if opt == '-h':
|
|
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>'
|
|
sys.exit(1)
|
|
elif opt == '-o':
|
|
output_img = arg
|
|
elif opt in ("--img_loader"):
|
|
img_loader = arg
|
|
stage1 = 1
|
|
elif opt in ("--img_bl1"):
|
|
img_bl1 = arg
|
|
stage1 = 1
|
|
elif opt in ("--img_prm_ptable"):
|
|
img_prm_ptable = arg
|
|
stage2 = 1
|
|
elif opt in ("--img_sec_ptable"):
|
|
img_sec_ptable = arg
|
|
|
|
loader = generator(output_img)
|
|
loader.idx = 0
|
|
|
|
if (stage1 == 1) and (stage2 == 1):
|
|
print 'There are only loader & BL1 in stage1.'
|
|
print 'And there are primary partition table, secondary partition table and FIP in stage2.'
|
|
sys.exit(1)
|
|
elif (stage1 == 0) and (stage2 == 0):
|
|
print 'No input images are specified.'
|
|
sys.exit(1)
|
|
elif stage1 == 1:
|
|
loader.create_stage1(img_loader, img_bl1, output_img)
|
|
elif stage2 == 1:
|
|
loader.create_stage2(img_prm_ptable, img_sec_ptable, output_img)
|
|
|
|
loader.end()
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|