xref: /rk3399_ARM-atf/tools/sptool/sptool.py (revision 2e82874cc9b7922e000dd4d7718e3153e347b1d7)
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