140681896Sopenharmony_ci#!/usr/bin/env python3
240681896Sopenharmony_ci# -*- coding: utf-8 -*-
340681896Sopenharmony_ci
440681896Sopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
540681896Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
640681896Sopenharmony_ci# you may not use this file except in compliance with the License.
740681896Sopenharmony_ci# You may obtain a copy of the License at
840681896Sopenharmony_ci#
940681896Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
1040681896Sopenharmony_ci#
1140681896Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
1240681896Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
1340681896Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1440681896Sopenharmony_ci# See the License for the specific language governing permissions and
1540681896Sopenharmony_ci# limitations under the License.
1640681896Sopenharmony_ci
1740681896Sopenharmony_ciimport os
1840681896Sopenharmony_ciimport sys
1940681896Sopenharmony_ciimport argparse
2040681896Sopenharmony_ciimport subprocess
2140681896Sopenharmony_ciimport secrets
2240681896Sopenharmony_ci
2340681896Sopenharmony_ciMOUNT_POINT = "/module_update"
2440681896Sopenharmony_ciBLOCK_SIZE = 4096
2540681896Sopenharmony_ciHASH_SIZE = 32
2640681896Sopenharmony_ciIMG_MARGIN_SIZE = 16777216
2740681896Sopenharmony_ci
2840681896Sopenharmony_ci
2940681896Sopenharmony_cidef run_cmd(cmd):
3040681896Sopenharmony_ci    res = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE,
3140681896Sopenharmony_ci                           stderr=subprocess.PIPE)
3240681896Sopenharmony_ci    sout, serr = res.communicate(timeout=120)
3340681896Sopenharmony_ci
3440681896Sopenharmony_ci    return res.pid, res.returncode, sout, serr
3540681896Sopenharmony_ci
3640681896Sopenharmony_ci
3740681896Sopenharmony_cidef verify_ret(res):
3840681896Sopenharmony_ci    if res[1]:
3940681896Sopenharmony_ci        print(" ".join(["pid ", str(res[0]), " ret ", str(res[1]), "\n",
4040681896Sopenharmony_ci                        res[2].decode(), res[3].decode()]))
4140681896Sopenharmony_ci        print("MkImages failed errno: %s" % str(res[1]))
4240681896Sopenharmony_ci        sys.exit(2)
4340681896Sopenharmony_ci
4440681896Sopenharmony_ci
4540681896Sopenharmony_cidef sparse_img2simg(is_sparse, device):
4640681896Sopenharmony_ci    # we don't support sparse in mktools.
4740681896Sopenharmony_ci    if "sparse" in is_sparse:
4840681896Sopenharmony_ci        tmp_device = "%s.tmp" % device
4940681896Sopenharmony_ci        run_cmd(" ".join(["img2simg ", device, " ", tmp_device]))
5040681896Sopenharmony_ci        os.rename(tmp_device, device)
5140681896Sopenharmony_ci
5240681896Sopenharmony_ci
5340681896Sopenharmony_cidef getdirsize(target_dir):
5440681896Sopenharmony_ci    size = 0
5540681896Sopenharmony_ci    for root, dirs, files in os.walk(target_dir):
5640681896Sopenharmony_ci        size += sum([roundup(os.path.getsize(os.path.join(root, name)), BLOCK_SIZE) for name in files])
5740681896Sopenharmony_ci    return size
5840681896Sopenharmony_ci
5940681896Sopenharmony_ci
6040681896Sopenharmony_cidef roundup(size, unit):
6140681896Sopenharmony_ci    return (size + unit - 1) & (~(unit - 1))
6240681896Sopenharmony_ci
6340681896Sopenharmony_ci
6440681896Sopenharmony_cidef resize_img(device):
6540681896Sopenharmony_ci    run_cmd(" ".join(["resize2fs", "-M", device]))
6640681896Sopenharmony_ci
6740681896Sopenharmony_ci
6840681896Sopenharmony_cidef get_hash_tree_size(img_size):
6940681896Sopenharmony_ci    treesize = 0
7040681896Sopenharmony_ci    size = img_size
7140681896Sopenharmony_ci    while size > BLOCK_SIZE:
7240681896Sopenharmony_ci        blocknum = size // BLOCK_SIZE
7340681896Sopenharmony_ci        level_size = roundup(blocknum * HASH_SIZE, BLOCK_SIZE)
7440681896Sopenharmony_ci        treesize += level_size
7540681896Sopenharmony_ci        size = level_size
7640681896Sopenharmony_ci    return treesize
7740681896Sopenharmony_ci
7840681896Sopenharmony_ci
7940681896Sopenharmony_cidef sign_img(device, pubkey, privkey, output):
8040681896Sopenharmony_ci    hvb_tools = "hvbtool.py"
8140681896Sopenharmony_ci    source_image = device
8240681896Sopenharmony_ci    partition = "update"
8340681896Sopenharmony_ci    img_size = os.path.getsize(device)
8440681896Sopenharmony_ci    partition_size = img_size + get_hash_tree_size(img_size) + BLOCK_SIZE
8540681896Sopenharmony_ci    salt = secrets.token_hex(20)
8640681896Sopenharmony_ci    algorithm = "SHA256_RSA2048"
8740681896Sopenharmony_ci    rollback_index = "0"
8840681896Sopenharmony_ci    rollback_location = "0"
8940681896Sopenharmony_ci    run_cmd(" ".join([hvb_tools, "make_hashtree_footer", "--image", device,
9040681896Sopenharmony_ci        "--partition", partition,
9140681896Sopenharmony_ci        "--partition_size", str(partition_size),
9240681896Sopenharmony_ci        "--salt", salt,
9340681896Sopenharmony_ci        "--pubkey", pubkey,
9440681896Sopenharmony_ci        "--privkey", privkey,
9540681896Sopenharmony_ci        "--algorithm", algorithm,
9640681896Sopenharmony_ci        "--rollback_index", rollback_index,
9740681896Sopenharmony_ci        "--rollback_location", rollback_location,
9840681896Sopenharmony_ci        "--output", output]))
9940681896Sopenharmony_ci
10040681896Sopenharmony_ci
10140681896Sopenharmony_cidef build_image(args):
10240681896Sopenharmony_ci    image_type = "raw"
10340681896Sopenharmony_ci    if args.sparse_image:
10440681896Sopenharmony_ci        image_type = "sparse"
10540681896Sopenharmony_ci    if args.build_image_tools_path:
10640681896Sopenharmony_ci        env_path = ':'.join(args.build_image_tools_path)
10740681896Sopenharmony_ci        os.environ['PATH'] = '{}:{}'.format(env_path, os.environ.get('PATH'))
10840681896Sopenharmony_ci    src_dir = args.input_path
10940681896Sopenharmony_ci    device = args.output_image_path
11040681896Sopenharmony_ci    is_sparse = image_type
11140681896Sopenharmony_ci    if "ext4" == args.fs_type:
11240681896Sopenharmony_ci        fs_type = "ext4"
11340681896Sopenharmony_ci        mkfs_tools = "mkextimage.py"
11440681896Sopenharmony_ci    elif "f2fs" == args.fs_type:
11540681896Sopenharmony_ci        fs_type = "f2fs"
11640681896Sopenharmony_ci        mkfs_tools = "mkf2fsimage.py"
11740681896Sopenharmony_ci    elif "cpio" == args.fs_type:
11840681896Sopenharmony_ci        fs_type = "cpio"
11940681896Sopenharmony_ci        mkfs_tools = "mkcpioimage.py"
12040681896Sopenharmony_ci    else:
12140681896Sopenharmony_ci        print("not support filesystem type!!")
12240681896Sopenharmony_ci        sys.exit(1)
12340681896Sopenharmony_ci
12440681896Sopenharmony_ci    fs_size = getdirsize(src_dir) + IMG_MARGIN_SIZE
12540681896Sopenharmony_ci    fs_type_config = "--fs_type=" + fs_type
12640681896Sopenharmony_ci    dac_config = args.dac_config
12740681896Sopenharmony_ci    file_context = args.file_context
12840681896Sopenharmony_ci
12940681896Sopenharmony_ci    mk_configs = " ".join([src_dir, device, MOUNT_POINT, str(fs_size), fs_type_config,
13040681896Sopenharmony_ci        "--dac_config", dac_config, "--file_context", file_context])
13140681896Sopenharmony_ci    res = run_cmd(" ".join([mkfs_tools, mk_configs]))
13240681896Sopenharmony_ci    verify_ret(res)
13340681896Sopenharmony_ci    sparse_img2simg(is_sparse, device)
13440681896Sopenharmony_ci    resize_img(device)
13540681896Sopenharmony_ci    if args.pubkey:
13640681896Sopenharmony_ci        sign_img(device, args.pubkey, args.privkey, args.output_sign_image_path)
13740681896Sopenharmony_ci    else:
13840681896Sopenharmony_ci        print("not sign image")
13940681896Sopenharmony_ci
14040681896Sopenharmony_ci
14140681896Sopenharmony_cidef main(argv):
14240681896Sopenharmony_ci    parser = argparse.ArgumentParser()
14340681896Sopenharmony_ci    parser.add_argument('--image-name', required=True)
14440681896Sopenharmony_ci    parser.add_argument('--fs-type', required=True)
14540681896Sopenharmony_ci    parser.add_argument('--dac-config', required=True)
14640681896Sopenharmony_ci    parser.add_argument('--file-context', required=True)
14740681896Sopenharmony_ci    parser.add_argument('--input-path', required=True)
14840681896Sopenharmony_ci    parser.add_argument('--output-image-path', required=True)
14940681896Sopenharmony_ci    parser.add_argument('--sparse-image',
15040681896Sopenharmony_ci                        dest="sparse_image",
15140681896Sopenharmony_ci                        action='store_true')
15240681896Sopenharmony_ci    parser.set_defaults(sparse_image=False)
15340681896Sopenharmony_ci    parser.add_argument('--build-image-tools-path', nargs='*', required=False)
15440681896Sopenharmony_ci    parser.add_argument('--target-cpu', required=False)
15540681896Sopenharmony_ci    parser.add_argument('--pubkey', required=False)
15640681896Sopenharmony_ci    parser.add_argument('--privkey', required=False)
15740681896Sopenharmony_ci    parser.add_argument('--output-sign-image-path', required=False)
15840681896Sopenharmony_ci    args = parser.parse_args(argv)
15940681896Sopenharmony_ci
16040681896Sopenharmony_ci    if os.path.exists(args.output_image_path):
16140681896Sopenharmony_ci        os.remove(args.output_image_path)
16240681896Sopenharmony_ci    if os.path.isdir(args.input_path):
16340681896Sopenharmony_ci        build_image(args)
16440681896Sopenharmony_ci    return 0
16540681896Sopenharmony_ci
16640681896Sopenharmony_ci
16740681896Sopenharmony_ciif __name__ == '__main__':
16840681896Sopenharmony_ci    sys.exit(main(sys.argv[1:]))
169