From: Łukasz Stelmach Date: Thu, 21 Sep 2023 20:01:43 +0000 (+0200) Subject: WIP: build a super partition image X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4cfe98427291bc0ff03a1ae5c895eb40c5c45470;p=platform%2Fkernel%2Fu-boot.git WIP: build a super partition image Change-Id: I7899e21faecc7c5d70b2792b31ad056a52801cb4 Signed-off-by: Łukasz Stelmach --- diff --git a/scripts/tizen/sd_fusing.py b/scripts/tizen/sd_fusing.py index f047245e5a..3df2f633ef 100755 --- a/scripts/tizen/sd_fusing.py +++ b/scripts/tizen/sd_fusing.py @@ -8,6 +8,7 @@ import errno import logging import os import re +import shutil import stat import subprocess import sys @@ -59,12 +60,14 @@ class Label: class SdFusingTarget: def __init__(self, device, ltype): + # TODO: make a copy of a sublcass part_table + self.with_super = False self.device = device total_size = device_size(device) self.user_size = total_size - self.reserved_space - \ reduce(lambda x, y: x + (y["size"] or 0), self.part_table, 0) if self.user_size < 100: - logging.error("Not enough space for user data. Use larger storage.") + logging.error(f"Not enough space for user data ({self.user_size}). Use larger storage.") raise OSError(errno.ENOSPC, os.strerror(errno.ENOSPC), device) self.part_table[self.user_partition]["size"] = self.user_size self.label = Label(self.part_table, ltype) @@ -195,7 +198,7 @@ class Rpi4Super(SdFusingTargetAB, RpiInitParams): self.update = args.update super().__init__(device, "gpt") self.with_super = True - + self.super_alignment = 1048576 class Rpi4(SdFusingTargetAB, RpiInitParams): long_name = "Raspberry Pi 4" @@ -240,6 +243,13 @@ class Rpi4(SdFusingTargetAB, RpiInitParams): "ramdisk-recovery.img": 15, "hal.img": 16, } + params = (('reboot-param.bin', 'norm'), + ('reboot-param.info', 'norm'), + ('partition-ab.info', 'a'), + ('partition-ab-cloned.info', '1'), + ('upgrade-status.info', '0'), + ('partition-a-status.info', 'ok'), + ('partition-b-status.info', 'ok')) def __init__(self, device, args): self.reserved_space = 5 @@ -324,13 +334,13 @@ def check_sfdisk(): return True, support_delete -def mkpart(args): +def mkpart(args, target): global Device new, support_delete = check_sfdisk() if not new: - sys.exit(1) - target = TARGETS[args.target](Device, args) + logging.error('sfdisk too old') + sys.exit(1) #TODO: unmount target devices if support_delete: @@ -436,7 +446,7 @@ def check_device(args): logging.error(f"{Device} is not a block device") sys.exit(1) -def check_partition_format(args): +def check_partition_format(args, target): global Format global Device @@ -444,7 +454,7 @@ def check_partition_format(args): logging.info(f"Skip formatting of {Device}".format(Device)) return logging.info(f"Start formatting of {Device}") - mkpart(args) + mkpart(args, target) logging.info(f"{Device} formatted") def check_ddversion(): @@ -492,9 +502,63 @@ def do_fuse_file(f, name, target): logging.info("Done") #TODO: verification -def do_fuse_image_tarball(tarball, target): +#TODO: functions with the target argument should probably +# be part of some class + +def get_aligned_size(size, target): + return target.super_alignment*int(1+(size-1)/target.super_alignment) + +def do_fuse_image_super(tmpd, target): + metadata_slots = 2 + metadata_size = 65536 + metadata_aligned_size = get_aligned_size(metadata_size, target) + + hal_path = os.path.join(tmpd, 'hal.img') + rootfs_path = os.path.join(tmpd, 'rootfs.img') + super_path = os.path.join(tmpd, 'super.img') + + try: + hal_size = os.stat(hal_path).st_size + rootfs_size = os.stat(rootfs_path).st_size + except FileNotFoundError as e: + fn = os.path.split(e.filename)[-1] + logging.warning(f"{fn} is missing, skipping super partition image") + return + + hal_aligned_size = get_aligned_size(hal_size, target) + rootfs_aligned_size = get_aligned_size(rootfs_size, target) + group_size = hal_aligned_size + rootfs_aligned_size + super_size = metadata_aligned_size + 2 * group_size + + proc = subprocess.run(["lpmake", "-F", + f"-o={super_path}", + f"--device-size={super_size}", + f"--metadata-size={metadata_size}", + f"--metadata-slots={metadata_slots}", + "-g", f"tizen_a:{group_size}", + "-p", f"rootfs_a:none:{rootfs_aligned_size}:tizen_a", + "-p", f"hal_a:none:{hal_aligned_size}:tizen_a", + "-g", f"tizen_b:{group_size}", + "-p", f"rootfs_b:none:{rootfs_aligned_size}:tizen_b", + "-p", f"hal_b:none:{hal_aligned_size}:tizen_b", + "-i", "rootfs_a={root_path}", + "-i", "rootfs_b={root_path}", + "-i", "hal_a={hal_path}", + "-i", "hal_b={hal_path}"], + stdin=subprocess.DEVNULL, + stdout=None, stderr=None) + + if proc.returncode != 0: + logging.error("Failed to create super.img") + do_fuse_image(super_path, target) + +def do_fuse_image_tarball(tarball, tmpd, target): with tarfile.open(tarball) as tf: for entry in tf: + if target.with_super: + if entry.name in('hal.img', 'rootfs.img'): + tf.extract(entry, path=tmpd) + continue f = tf.extractfile(entry) do_fuse_file(f, entry.name, target) @@ -502,16 +566,22 @@ def do_fuse_image(img, target): with open(img, 'rb') as f: do_fuse_file(f, img, target) -def fuse_image(args): +def fuse_image(args, target): if args.binaries is None or len(args.binaries) == 0: return - - target = TARGETS[args.target](Device, args) - for b in args.binaries: - if re.search('\.(tar|tar\.gz|tgz)$', b): - do_fuse_image_tarball(b, target) - else: - do_fuse_image(b, target) + with tempfile.TemporaryDirectory() as tmpd: + for b in args.binaries: + if re.search('\.(tar|tar\.gz|tgz)$', b): + do_fuse_image_tarball(b, tmpd, target) + else: + fn = os.path.split(b)[-1] + if target.with_super and fn in ('rootfs.img', 'hal.img'): + shutil.copy(b, os.path.join(tmpd, fn)) + else: + do_fuse_image(b, target) + + if target.with_super: + do_fuse_image_super(tmpd, target) if __name__ == '__main__': parser = argparse.ArgumentParser(description="For {}, version {}".format( @@ -550,8 +620,11 @@ if __name__ == '__main__': check_args(args) check_device(args) - check_partition_format(args) - fuse_image(args) + + target = TARGETS[args.target](Device, args) + + check_partition_format(args, target) + fuse_image(args, target) subprocess.run(['sync'], stdin=subprocess.DEVNULL, stdout=None, stderr=None )