diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py index d7816e55..67b79453 100644 --- a/pmb/config/__init__.py +++ b/pmb/config/__init__.py @@ -715,6 +715,9 @@ deviceinfo_attributes = [ "partition_type", "root_filesystem", "flash_kernel_on_update", + "cgpt_kpart", + "cgpt_kpart_start", + "cgpt_kpart_size", # weston "weston_pixman_type", diff --git a/pmb/helpers/frontend.py b/pmb/helpers/frontend.py index a533fda2..2f15b136 100644 --- a/pmb/helpers/frontend.py +++ b/pmb/helpers/frontend.py @@ -260,6 +260,10 @@ def install(args): if args.filesystem: raise ValueError("--on-device-installer cannot be combined with" " --filesystem") + + if args.deviceinfo["cgpt_kpart"]: + raise ValueError("--on-device-installer cannot be used with" + " ChromeOS devices") else: if args.ondev_cp: raise ValueError("--cp can only be combined with --ondev") diff --git a/pmb/install/__init__.py b/pmb/install/__init__.py index 15c8c57b..7163ee2d 100644 --- a/pmb/install/__init__.py +++ b/pmb/install/__init__.py @@ -3,6 +3,7 @@ from pmb.install._install import install from pmb.install._install import get_kernel_package from pmb.install.partition import partition +from pmb.install.partition import partition_cgpt from pmb.install.format import format from pmb.install.format import get_root_filesystem from pmb.install.partition import partitions_mount diff --git a/pmb/install/_install.py b/pmb/install/_install.py index cc1d1779..aaa672f3 100644 --- a/pmb/install/_install.py +++ b/pmb/install/_install.py @@ -553,6 +553,22 @@ def embed_firmware(args, suffix): "bs=" + str(step), "seek=" + str(offset)]) +def write_cgpt_kpart(args, layout, suffix): + """ + Write the kernel to the ChromeOS kernel partition. + + :param layout: partition layout from get_partition_layout() + :param suffix: of the chroot, which holds the image file to be flashed + """ + if not args.deviceinfo["cgpt_kpart"]: + return + + device_rootfs = mount_device_rootfs(args, suffix) + filename = f"{device_rootfs}{args.deviceinfo['cgpt_kpart']}" + pmb.chroot.root( + args, ["dd", f"if={filename}", f"of=/dev/installp{layout['kernel']}"]) + + def sanity_check_sdcard(args): device = args.sdcard device_name = os.path.basename(device) @@ -607,17 +623,25 @@ def sanity_check_ondev_version(args): f" / in the binary packages has version {ver_pkg}.") -def get_partition_layout(reserve): +def get_partition_layout(reserve, kernel): """ :param reserve: create an empty partition between root and boot (pma#463) + :param kernel: create a separate kernel partition before all other + partitions, e.g. for the ChromeOS devices with cgpt :returns: the partition layout, e.g. without reserve and kernel: - {"boot": 1, "reserve": None, "root": 2} + {"kernel": None, "boot": 1, "reserve": None, "root": 2} """ ret = {} + ret["kernel"] = None ret["boot"] = 1 ret["reserve"] = None ret["root"] = 2 + if kernel: + ret["kernel"] = 1 + ret["boot"] += 1 + ret["root"] += 1 + if reserve: ret["reserve"] = ret["root"] ret["root"] += 1 @@ -642,12 +666,16 @@ def install_system_image(args, size_reserve, suffix, step, steps, logging.info(f"*** ({step}/{steps}) PREPARE INSTALL BLOCKDEVICE ***") pmb.chroot.shutdown(args, True) (size_boot, size_root) = get_subpartitions_size(args, suffix) - layout = get_partition_layout(size_reserve) + layout = get_partition_layout(size_reserve, args.deviceinfo["cgpt_kpart"]) if not args.rsync: pmb.install.blockdevice.create(args, size_boot, size_root, size_reserve, split, sdcard) if not split: - pmb.install.partition(args, layout, size_boot, size_reserve) + if args.deviceinfo["cgpt_kpart"]: + pmb.install.partition_cgpt( + args, layout, size_boot, size_reserve) + else: + pmb.install.partition(args, layout, size_boot, size_reserve) if not split: pmb.install.partitions_mount(args, layout, sdcard) @@ -660,10 +688,11 @@ def install_system_image(args, size_reserve, suffix, step, steps, configure_apk(args) copy_ssh_keys(args) - # Don't try to embed firmware on split images since there's no + # Don't try to embed firmware and cgpt on split images since there's no # place to put it and it will end up in /dev of the chroot instead if not split: embed_firmware(args, suffix) + write_cgpt_kpart(args, layout, suffix) if sdcard: logging.info("Unmounting SD card (this may take a while " diff --git a/pmb/install/format.py b/pmb/install/format.py index a85179dc..d8d9a2d3 100644 --- a/pmb/install/format.py +++ b/pmb/install/format.py @@ -13,15 +13,15 @@ def install_fsprogs(args, filesystem): pmb.chroot.apk.install(args, [fsprogs]) -def format_and_mount_boot(args, boot_label): +def format_and_mount_boot(args, device, boot_label): """ + :param device: boot partition on install block device (e.g. /dev/installp1) :param boot_label: label of the root partition (e.g. "pmOS_boot") When adjusting this function, make sure to also adjust ondev-prepare-internal-storage.sh in postmarketos-ondev.git! """ mountpoint = "/mnt/install/boot" - device = "/dev/installp1" filesystem = args.deviceinfo["boot_filesystem"] or "ext2" install_fsprogs(args, filesystem) logging.info(f"(native) format {device} (boot, {filesystem}), mount to" @@ -133,10 +133,11 @@ def format(args, layout, boot_label, root_label, sdcard): :param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None """ root_dev = f"/dev/installp{layout['root']}" + boot_dev = f"/dev/installp{layout['boot']}" if args.full_disk_encryption: format_luks_root(args, root_dev) root_dev = "/dev/mapper/pm_crypt" format_and_mount_root(args, root_dev, root_label, sdcard) - format_and_mount_boot(args, boot_label) + format_and_mount_boot(args, boot_dev, boot_label) diff --git a/pmb/install/partition.py b/pmb/install/partition.py index 02ac5686..57230a8f 100644 --- a/pmb/install/partition.py +++ b/pmb/install/partition.py @@ -37,7 +37,12 @@ def partitions_mount(args, layout, sdcard): prefix + " to be located at " + prefix + "1 or " + prefix + "p1!") - for i in [1, layout["root"]]: + partitions = [layout["boot"], layout["root"]] + + if layout["kernel"]: + partitions += [layout["kernel"]] + + for i in partitions: source = prefix + partition_prefix + str(i) target = args.work + "/chroot_native/dev/installp" + str(i) pmb.helpers.mount.bind_file(args, source, target) @@ -91,3 +96,93 @@ def partition(args, layout, size_boot, size_reserve): for command in commands: pmb.chroot.root(args, ["parted", "-s", "/dev/install"] + command, check=False) + + +def partition_cgpt(args, layout, size_boot, size_reserve): + """ + This function does similar functionality to partition(), but this + one is for ChromeOS devices which use special GPT. + + :param layout: partition layout from get_partition_layout() + :param size_boot: size of the boot partition in MiB + :param size_reserve: empty partition between root and boot in MiB (pma#463) + """ + + pmb.chroot.root(args, ["apk", "add", "cgpt"]) + + cgpt = { + 'kpart_start': args.deviceinfo["cgpt_kpart_start"], + 'kpart_size': args.deviceinfo["cgpt_kpart_size"], + } + + # Convert to MB and print info + mb_boot = f"{round(size_boot)}M" + mb_reserved = f"{round(size_reserve)}M" + logging.info(f"(native) partition /dev/install (boot: {mb_boot}," + f" reserved: {mb_reserved}, root: the rest)") + + boot_part_start = str(int(cgpt['kpart_start']) + int(cgpt['kpart_size'])) + + # Convert to sectors + s_boot = str(int(size_boot * 1024 * 1024 / 512)) + s_root_start = str(int( + int(boot_part_start) + int(s_boot) + size_reserve * 1024 * 1024 / 512 + )) + + commands = [ + ["parted", "-s", "/dev/install", "mktable", "gpt"], + ["cgpt", "create", "/dev/install"], + [ + "cgpt", "add", + # pmOS_boot is second partition, the first will be ChromeOS kernel + # partition + "-i", str(layout["boot"]), # Partition number + "-t", "data", + "-b", boot_part_start, + "-s", s_boot, + "-l", "pmOS_boot", + "/dev/install" + ], + # Mark this partition as bootable for u-boot + [ + "parted", + "-s", "/dev/install", + "set", str(layout["boot"]), + "boot", "on" + ], + # For some reason cgpt switches all flags to 0 after marking + # any partition as bootable, so create ChromeOS kernel partition + # only after pmOS_boot is created and marked as bootable + [ + "cgpt", "add", + "-i", str(layout["kernel"]), + "-t", "kernel", + "-b", cgpt['kpart_start'], + "-s", cgpt['kpart_size'], + "-l", "Kernel", + "-S", "1", # Successful flag + "-T", "5", # Tries flag + "-P", "10", # Priority flag + "/dev/install" + ], + ] + + dev_size = pmb.chroot.root( + args, ["blockdev", "--getsz", "/dev/install"], output_return=True) + root_size = str(int(dev_size) - int(s_root_start) - 1024) + + commands += [ + [ + "cgpt", "add", + "-i", str(layout["root"]), + "-t", "data", + "-b", s_root_start, + "-s", root_size, + "-l", "pmOS_root", + "/dev/install" + ], + ["partx", "-a", "/dev/install"] + ] + + for command in commands: + pmb.chroot.root(args, command, check=False)