blob: 46fc36afeeff9c57694cbdd96b48149387d07283 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2020 The Hafnium Authors.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/BSD-3-Clause.
"""Script which generates a Secure Partition package.
https://trustedfirmware-a.readthedocs.io/en/latest/components/secure-partition-manager.html#secure-partition-packages
"""
import argparse
import sys
from shutil import copyfileobj
import os
HF_PAGE_SIZE = 0x1000
HEADER_ELEMENT_BYTES = 4 # bytes
HEADER_LEN = 6
MANIFEST_IMAGE_SPLITTER=':'
def split_dtb_bin(i : str):
return i.split(MANIFEST_IMAGE_SPLITTER)
def align_to_page(n):
return HF_PAGE_SIZE * \
(round(n / HF_PAGE_SIZE) + \
(1 if n % HF_PAGE_SIZE else 0))
def to_bytes(value):
return int(value).to_bytes(4, 'little')
class sp_pkg_info:
def __init__(self, manifest_path : str, image_path : str, include_header = True):
if not os.path.isfile(manifest_path) or not os.path.isfile(image_path):
raise Exception(f"Parameters should be path. \
manifest: {manifest_path}; image: {image_path}")
self.manifest_path = manifest_path
self.image_path = image_path
self.include_header = include_header
def __str__(self):
return \
f'''-------------------SP package Info------------------------
header:{self.header}
manifest: {self.manifest_path}
image: {self.image_path}
'''
@property
def magic(self):
return "SPKG".encode()
@property
def version(self):
return 1
@property
def manifest_offset(self):
return self.header_size if self.include_header else 0
@property
def manifest_size(self):
return os.path.getsize(self.manifest_path)
@property
def image_offset(self):
return align_to_page(self.manifest_offset + self.manifest_size)
@property
def image_size(self):
return os.path.getsize(self.image_path)
@property
def header(self):
return [self.magic,
self.version,
self.manifest_offset,
self.manifest_size,
self.image_offset,
self.image_size]
@property
def header_size(self):
return (HEADER_ELEMENT_BYTES * HEADER_LEN)
def generate_package(self, f_out : str):
with open(f_out, "wb+") as output:
if self.include_header is True:
for h in self.header:
to_write = h if type(h) is bytes else to_bytes(h)
output.write(to_write)
with open(self.manifest_path, "rb") as manifest:
copyfileobj(manifest, output)
output.seek(self.image_offset, 0)
with open(self.image_path, "rb") as image:
copyfileobj(image, output)
def Main():
parser = argparse.ArgumentParser()
parser.add_argument("-i", required=True,
help="Add Secure Partition image and Manifest blob "
"(specified in two paths) separated by a colon).")
parser.add_argument("-o", required=True, help="Set output file path.")
parser.add_argument("-n", required=False, action="store_true", default=False,
help="Generate package without header.")
args = parser.parse_args()
if not os.path.exists(os.path.dirname(args.o)):
raise Exception("Provide a valid output file path!\n")
image_path, manifest_path = split_dtb_bin(args.i)
pkg = sp_pkg_info(manifest_path, image_path, not args.n)
pkg.generate_package(args.o)
return 0
if __name__ == "__main__":
sys.exit(Main())