1*91f16700Schasinglulu#!/usr/bin/python3 2*91f16700Schasinglulu# Copyright (c) 2022, Arm Limited. All rights reserved. 3*91f16700Schasinglulu# 4*91f16700Schasinglulu# SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu 6*91f16700Schasinglulu# 7*91f16700Schasinglulu# Copyright 2022 The Hafnium Authors. 8*91f16700Schasinglulu# 9*91f16700Schasinglulu# Use of this source code is governed by a BSD-style 10*91f16700Schasinglulu# license that can be found in the LICENSE file or at 11*91f16700Schasinglulu# https://opensource.org/licenses/BSD-3-Clause. 12*91f16700Schasinglulu 13*91f16700Schasinglulu""" 14*91f16700SchasingluluScript which generates a Secure Partition package. 15*91f16700Schasingluluhttps://trustedfirmware-a.readthedocs.io/en/latest/components/secure-partition-manager.html#secure-partition-packages 16*91f16700Schasinglulu""" 17*91f16700Schasinglulu 18*91f16700Schasingluluimport argparse 19*91f16700Schasinglulufrom collections import namedtuple 20*91f16700Schasingluluimport sys 21*91f16700Schasinglulufrom shutil import copyfileobj 22*91f16700Schasingluluimport os 23*91f16700Schasinglulu 24*91f16700SchasingluluHF_PAGE_SIZE = 0x1000 # bytes 25*91f16700SchasingluluHEADER_ELEMENT_BYTES = 4 # bytes 26*91f16700SchasingluluMANIFEST_IMAGE_SPLITTER=':' 27*91f16700SchasingluluPM_OFFSET_DEFAULT = "0x1000" 28*91f16700SchasingluluIMG_OFFSET_DEFAULT = "0x4000" 29*91f16700Schasinglulu 30*91f16700Schasingluludef split_dtb_bin(i : str): 31*91f16700Schasinglulu return i.split(MANIFEST_IMAGE_SPLITTER) 32*91f16700Schasinglulu 33*91f16700Schasingluludef align_to_page(n): 34*91f16700Schasinglulu return HF_PAGE_SIZE * \ 35*91f16700Schasinglulu (round(n / HF_PAGE_SIZE) + \ 36*91f16700Schasinglulu (1 if n % HF_PAGE_SIZE else 0)) 37*91f16700Schasinglulu 38*91f16700Schasingluludef to_bytes(value): 39*91f16700Schasinglulu return int(value).to_bytes(HEADER_ELEMENT_BYTES, 'little') 40*91f16700Schasinglulu 41*91f16700Schasingluluclass SpPkg: 42*91f16700Schasinglulu def __init__(self, pm_path : str, img_path : str, pm_offset: int, 43*91f16700Schasinglulu img_offset: int): 44*91f16700Schasinglulu if not os.path.isfile(pm_path) or not os.path.isfile(img_path): 45*91f16700Schasinglulu raise Exception(f"Parameters should be path. \ 46*91f16700Schasinglulu manifest: {pm_path}; img: {img_path}") 47*91f16700Schasinglulu self.pm_path = pm_path 48*91f16700Schasinglulu self.img_path = img_path 49*91f16700Schasinglulu self._SpPkgHeader = namedtuple("SpPkgHeader", 50*91f16700Schasinglulu ("magic", "version", 51*91f16700Schasinglulu "pm_offset", "pm_size", 52*91f16700Schasinglulu "img_offset", "img_size")) 53*91f16700Schasinglulu 54*91f16700Schasinglulu if pm_offset >= img_offset: 55*91f16700Schasinglulu raise ValueError("pm_offset must be smaller than img_offset") 56*91f16700Schasinglulu 57*91f16700Schasinglulu is_hfpage_aligned = lambda val : val % HF_PAGE_SIZE == 0 58*91f16700Schasinglulu if not is_hfpage_aligned(pm_offset) or not is_hfpage_aligned(img_offset): 59*91f16700Schasinglulu raise ValueError(f"Offsets provided need to be page aligned: pm-{pm_offset}, img-{img_offset}") 60*91f16700Schasinglulu 61*91f16700Schasinglulu if img_offset - pm_offset < self.pm_size: 62*91f16700Schasinglulu raise ValueError(f"pm_offset and img_offset do not fit the specified file:{pm_path})") 63*91f16700Schasinglulu 64*91f16700Schasinglulu self.pm_offset = pm_offset 65*91f16700Schasinglulu self.img_offset = img_offset 66*91f16700Schasinglulu 67*91f16700Schasinglulu def __str__(self): 68*91f16700Schasinglulu return \ 69*91f16700Schasinglulu f'''--SP package Info-- 70*91f16700Schasinglulu header:{self.header} 71*91f16700Schasinglulu pm: {self.pm_path} 72*91f16700Schasinglulu img: {self.img_path} 73*91f16700Schasinglulu ''' 74*91f16700Schasinglulu 75*91f16700Schasinglulu @property 76*91f16700Schasinglulu def magic(self): 77*91f16700Schasinglulu return "SPKG".encode() 78*91f16700Schasinglulu 79*91f16700Schasinglulu @property 80*91f16700Schasinglulu def version(self): 81*91f16700Schasinglulu return 0x2 82*91f16700Schasinglulu 83*91f16700Schasinglulu @property 84*91f16700Schasinglulu def pm_size(self): 85*91f16700Schasinglulu return os.path.getsize(self.pm_path) 86*91f16700Schasinglulu 87*91f16700Schasinglulu @property 88*91f16700Schasinglulu def img_size(self): 89*91f16700Schasinglulu return os.path.getsize(self.img_path) 90*91f16700Schasinglulu 91*91f16700Schasinglulu @property 92*91f16700Schasinglulu def header(self): 93*91f16700Schasinglulu return self._SpPkgHeader( 94*91f16700Schasinglulu self.magic, 95*91f16700Schasinglulu self.version, 96*91f16700Schasinglulu self.pm_offset, 97*91f16700Schasinglulu self.pm_size, 98*91f16700Schasinglulu self.img_offset, 99*91f16700Schasinglulu self.img_size) 100*91f16700Schasinglulu 101*91f16700Schasinglulu @property 102*91f16700Schasinglulu def header_size(self): 103*91f16700Schasinglulu return len(self._SpPkgHeader._fields) 104*91f16700Schasinglulu 105*91f16700Schasinglulu def generate(self, f_out : str): 106*91f16700Schasinglulu with open(f_out, "wb+") as output: 107*91f16700Schasinglulu for h in self.header: 108*91f16700Schasinglulu to_write = h if type(h) is bytes else to_bytes(h) 109*91f16700Schasinglulu output.write(to_write) 110*91f16700Schasinglulu output.seek(self.pm_offset) 111*91f16700Schasinglulu with open(self.pm_path, "rb") as pm: 112*91f16700Schasinglulu copyfileobj(pm, output) 113*91f16700Schasinglulu output.seek(self.img_offset) 114*91f16700Schasinglulu with open(self.img_path, "rb") as img: 115*91f16700Schasinglulu copyfileobj(img, output) 116*91f16700Schasinglulu 117*91f16700Schasingluludef Main(): 118*91f16700Schasinglulu parser = argparse.ArgumentParser() 119*91f16700Schasinglulu parser.add_argument("-i", required=True, 120*91f16700Schasinglulu help="path to partition's image and manifest separated by a colon.") 121*91f16700Schasinglulu parser.add_argument("--pm-offset", required=False, default=PM_OFFSET_DEFAULT, 122*91f16700Schasinglulu help="set partitition manifest offset.") 123*91f16700Schasinglulu parser.add_argument("--img-offset", required=False, default=IMG_OFFSET_DEFAULT, 124*91f16700Schasinglulu help="set partition image offset.") 125*91f16700Schasinglulu parser.add_argument("-o", required=True, help="set output file path.") 126*91f16700Schasinglulu parser.add_argument("-v", required=False, action="store_true", 127*91f16700Schasinglulu help="print package information.") 128*91f16700Schasinglulu args = parser.parse_args() 129*91f16700Schasinglulu 130*91f16700Schasinglulu if not os.path.exists(os.path.dirname(args.o)): 131*91f16700Schasinglulu raise Exception("Provide a valid output file path!\n") 132*91f16700Schasinglulu 133*91f16700Schasinglulu image_path, manifest_path = split_dtb_bin(args.i) 134*91f16700Schasinglulu pm_offset = int(args.pm_offset, 0) 135*91f16700Schasinglulu img_offset = int(args.img_offset, 0) 136*91f16700Schasinglulu pkg = SpPkg(manifest_path, image_path, pm_offset, img_offset) 137*91f16700Schasinglulu pkg.generate(args.o) 138*91f16700Schasinglulu 139*91f16700Schasinglulu if args.v is True: 140*91f16700Schasinglulu print(pkg) 141*91f16700Schasinglulu 142*91f16700Schasinglulu return 0 143*91f16700Schasinglulu 144*91f16700Schasingluluif __name__ == "__main__": 145*91f16700Schasinglulu sys.exit(Main()) 146