arm-trusted-firmware/tools/sptool/sptool.py
J-Alves 2e82874cc9 feat(sptool): python version of the sptool
To cope with the changes/design decisions in the implementation of
boot protocol, from FF-A v1.1 specification in the S-EL2 SPM, we have
changed the format of the sp pkg header.
These changes need to be reflected in the sptool, used for packaging
the SP binary, and the SP's FF-A manifest. Now the SP pkg can
contain the boot information blob as defined by the FF-A specification.
To cater for these changes, bring to the TF-A project an equivalent to
the tool used in the Hafnium project.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I046f5d6e3c2ef0ba6c87f65302e127dedef34c28
2022-05-04 15:36:56 +01:00

145 lines
4.6 KiB
Python
Executable file

#!/usr/bin/python3
# Copyright (c) 2022, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Copyright 2022 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
from collections import namedtuple
import sys
from shutil import copyfileobj
import os
HF_PAGE_SIZE = 0x1000 # bytes
HEADER_ELEMENT_BYTES = 4 # bytes
MANIFEST_IMAGE_SPLITTER=':'
PM_OFFSET_DEFAULT = "0x1000"
IMG_OFFSET_DEFAULT = "0x4000"
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(HEADER_ELEMENT_BYTES, 'little')
class SpPkg:
def __init__(self, pm_path : str, img_path : str, pm_offset: int,
img_offset: int):
if not os.path.isfile(pm_path) or not os.path.isfile(img_path):
raise Exception(f"Parameters should be path. \
manifest: {pm_path}; img: {img_path}")
self.pm_path = pm_path
self.img_path = img_path
self._SpPkgHeader = namedtuple("SpPkgHeader",
("magic", "version",
"pm_offset", "pm_size",
"img_offset", "img_size"))
if pm_offset >= img_offset:
raise ValueError("pm_offset must be smaller than img_offset")
is_hfpage_aligned = lambda val : val % HF_PAGE_SIZE == 0
if not is_hfpage_aligned(pm_offset) or not is_hfpage_aligned(img_offset):
raise ValueError(f"Offsets provided need to be page aligned: pm-{pm_offset}, img-{img_offset}")
if img_offset - pm_offset < self.pm_size:
raise ValueError(f"pm_offset and img_offset do not fit the specified file:{pm_path})")
self.pm_offset = pm_offset
self.img_offset = img_offset
def __str__(self):
return \
f'''--SP package Info--
header:{self.header}
pm: {self.pm_path}
img: {self.img_path}
'''
@property
def magic(self):
return "SPKG".encode()
@property
def version(self):
return 0x2
@property
def pm_size(self):
return os.path.getsize(self.pm_path)
@property
def img_size(self):
return os.path.getsize(self.img_path)
@property
def header(self):
return self._SpPkgHeader(
self.magic,
self.version,
self.pm_offset,
self.pm_size,
self.img_offset,
self.img_size)
@property
def header_size(self):
return len(self._SpPkgHeader._fields)
def generate(self, f_out : str):
with open(f_out, "wb+") as output:
for h in self.header:
to_write = h if type(h) is bytes else to_bytes(h)
output.write(to_write)
output.seek(self.pm_offset)
with open(self.pm_path, "rb") as pm:
copyfileobj(pm, output)
output.seek(self.img_offset)
with open(self.img_path, "rb") as img:
copyfileobj(img, output)
def Main():
parser = argparse.ArgumentParser()
parser.add_argument("-i", required=True,
help="path to partition's image and manifest separated by a colon.")
parser.add_argument("--pm-offset", required=False, default=PM_OFFSET_DEFAULT,
help="set partitition manifest offset.")
parser.add_argument("--img-offset", required=False, default=IMG_OFFSET_DEFAULT,
help="set partition image offset.")
parser.add_argument("-o", required=True, help="set output file path.")
parser.add_argument("-v", required=False, action="store_true",
help="print package information.")
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)
pm_offset = int(args.pm_offset, 0)
img_offset = int(args.img_offset, 0)
pkg = SpPkg(manifest_path, image_path, pm_offset, img_offset)
pkg.generate(args.o)
if args.v is True:
print(pkg)
return 0
if __name__ == "__main__":
sys.exit(Main())