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