Support ChromeOS partition table and kernel partition (MR 2163)

Stock bootloader on these devices boots kernel (it is intended to boot
kernel, but i place secondary bootloader there) from special ChromeOS
kernel partition on special GPT which is created with cgpt utility.
This MR adds initial support for it introducing new deviceinfo options:

- cgpt_kpart - path to file to be flashed to ChromeOS partition;
- cgpt_kpart_start - offset from the start in sectors;
- cgpt_kpart_size - partition size in sectors.

For example:

deviceinfo_cgpt_kpart="/usr/share/u-boot/google-peach-pit/u-boot-dtb.img.kpart"
deviceinfo_cgpt_kpart_start="8192"
deviceinfo_cgpt_kpart_size="32768"

cgpt requires start and size values of partition, so these values
are calculated for each partition.

Reserved size and on-device installer are not yet supported.

Reference: https://archlinuxarm.org/platforms/armv7/samsung/samsung-chromebook
This commit is contained in:
jenneron 2022-01-29 01:52:36 +02:00 committed by Oliver Smith
parent 2363732645
commit 7b2ffc3e5f
No known key found for this signature in database
GPG Key ID: 5AE7F5513E0885CB
6 changed files with 142 additions and 9 deletions

View File

@ -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",

View File

@ -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")

View File

@ -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

View File

@ -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 "

View File

@ -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)

View File

@ -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)