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