Olivier Deprez | 06c4cbd | 2020-10-02 15:31:33 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright 2020 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 | """Script which generates a Secure Partition package. |
| 10 | https://trustedfirmware-a.readthedocs.io/en/latest/components/secure-partition-manager.html#secure-partition-packages |
| 11 | """ |
| 12 | |
| 13 | import argparse |
| 14 | import sys |
| 15 | from shutil import copyfileobj |
| 16 | import os |
| 17 | |
| 18 | HF_PAGE_SIZE = 0x1000 |
| 19 | HEADER_ELEMENT_BYTES = 4 # bytes |
| 20 | HEADER_LEN = 6 |
| 21 | |
| 22 | MANIFEST_IMAGE_SPLITTER=':' |
| 23 | def split_dtb_bin(i : str): |
| 24 | return i.split(MANIFEST_IMAGE_SPLITTER) |
| 25 | |
| 26 | def align_to_page(n): |
| 27 | return HF_PAGE_SIZE * \ |
| 28 | (round(n / HF_PAGE_SIZE) + \ |
| 29 | (1 if n % HF_PAGE_SIZE else 0)) |
| 30 | |
| 31 | def to_bytes(value): |
| 32 | return int(value).to_bytes(4, 'little') |
| 33 | |
| 34 | class sp_pkg_info: |
| 35 | def __init__(self, manifest_path : str, image_path : str, include_header = True): |
| 36 | if not os.path.isfile(manifest_path) or not os.path.isfile(image_path): |
| 37 | raise Exception(f"Parameters should be path. \ |
| 38 | manifest: {manifest_path}; image: {image_path}") |
| 39 | self.manifest_path = manifest_path |
| 40 | self.image_path = image_path |
| 41 | self.include_header = include_header |
| 42 | |
| 43 | def __str__(self): |
| 44 | return \ |
| 45 | f'''-------------------SP package Info------------------------ |
| 46 | header:{self.header} |
| 47 | manifest: {self.manifest_path} |
| 48 | image: {self.image_path} |
| 49 | ''' |
| 50 | |
| 51 | @property |
| 52 | def magic(self): |
| 53 | return "SPKG".encode() |
| 54 | |
| 55 | @property |
| 56 | def version(self): |
| 57 | return 1 |
| 58 | |
| 59 | @property |
| 60 | def manifest_offset(self): |
| 61 | return self.header_size if self.include_header else 0 |
| 62 | |
| 63 | @property |
| 64 | def manifest_size(self): |
| 65 | return os.path.getsize(self.manifest_path) |
| 66 | |
| 67 | @property |
| 68 | def image_offset(self): |
| 69 | return align_to_page(self.manifest_offset + self.manifest_size) |
| 70 | |
| 71 | @property |
| 72 | def image_size(self): |
| 73 | return os.path.getsize(self.image_path) |
| 74 | |
| 75 | @property |
| 76 | def header(self): |
| 77 | return [self.magic, |
| 78 | self.version, |
| 79 | self.manifest_offset, |
| 80 | self.manifest_size, |
| 81 | self.image_offset, |
| 82 | self.image_size] |
| 83 | |
| 84 | @property |
| 85 | def header_size(self): |
| 86 | return (HEADER_ELEMENT_BYTES * HEADER_LEN) |
| 87 | |
| 88 | def generate_package(self, f_out : str): |
| 89 | with open(f_out, "wb+") as output: |
| 90 | if self.include_header is True: |
| 91 | for h in self.header: |
| 92 | to_write = h if type(h) is bytes else to_bytes(h) |
| 93 | output.write(to_write) |
| 94 | with open(self.manifest_path, "rb") as manifest: |
| 95 | copyfileobj(manifest, output) |
| 96 | output.seek(self.image_offset, 0) |
| 97 | with open(self.image_path, "rb") as image: |
| 98 | copyfileobj(image, output) |
| 99 | |
| 100 | def Main(): |
| 101 | parser = argparse.ArgumentParser() |
| 102 | parser.add_argument("-i", required=True, |
| 103 | help="Add Secure Partition image and Manifest blob " |
| 104 | "(specified in two paths) separated by a colon).") |
| 105 | parser.add_argument("-o", required=True, help="Set output file path.") |
| 106 | parser.add_argument("-n", required=False, action="store_true", default=False, |
| 107 | help="Generate package without header.") |
| 108 | args = parser.parse_args() |
| 109 | |
| 110 | if not os.path.exists(os.path.dirname(args.o)): |
| 111 | raise Exception("Provide a valid output file path!\n") |
| 112 | |
| 113 | image_path, manifest_path = split_dtb_bin(args.i) |
| 114 | pkg = sp_pkg_info(manifest_path, image_path, not args.n) |
| 115 | pkg.generate_package(args.o) |
| 116 | |
| 117 | return 0 |
| 118 | |
| 119 | if __name__ == "__main__": |
| 120 | sys.exit(Main()) |