| # Copyright 2021 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """MiniOS build library.""" |
| |
| import logging |
| import os |
| |
| from chromite.lib import build_target_lib |
| from chromite.lib import constants |
| from chromite.lib import cros_build_lib |
| from chromite.lib import image_lib |
| from chromite.lib import kernel_builder |
| |
| |
| CROS_DEBUG_FLAG = "cros_debug" |
| MINIOS_KERNEL_IMAGE = "minios_vmlinuz.image" |
| KERNEL_FLAGS = [ |
| "minios", |
| "minios_ramfs", |
| "tpm", |
| "i2cdev", |
| "vfat", |
| "kernel_compress_xz", |
| "pcserial", |
| "-kernel_afdo", |
| ] |
| BLOCK_SIZE = 512 |
| |
| |
| class Error(Exception): |
| """Base error class for the module.""" |
| |
| |
| class MiniOsError(Error): |
| """Raised when failing to build Mini OS image.""" |
| |
| |
| def CreateMiniOsKernelImage( |
| board: str, |
| version: str, |
| work_dir: str, |
| keys_dir: str, |
| public_key: str, |
| private_key: str, |
| keyblock: str, |
| serial: str, |
| jobs: int, |
| build_kernel: bool = True, |
| developer_mode: bool = False, |
| ) -> str: |
| """Creates the MiniOS kernel image. |
| |
| And puts it in the work directory. |
| |
| Args: |
| jobs: The number of packages to build in parallel. |
| board: The board to build the kernel for. |
| version: The chromeos version string. |
| work_dir: The directory for keeping intermediary files. |
| keys_dir: The path to kernel keys directories. |
| public_key: Filename to the public key whose private part signed the |
| keyblock. |
| private_key: Filename to the private key whose public part is baked into |
| the keyblock. |
| keyblock: Filename to the kernel keyblock. |
| serial: Serial port for the kernel console (e.g. printks). |
| build_kernel: Build a new kernel from source. |
| developer_mode: Add developer mode flags to the kernel image. |
| |
| Returns: |
| The path to the generated kernel image. |
| """ |
| install_root = os.path.join( |
| (build_target_lib.get_default_sysroot_path(board)), "factory-root" |
| ) |
| kb = kernel_builder.Builder(board, work_dir, install_root, jobs) |
| if build_kernel: |
| # MiniOS ramfs cannot be built with multiple conflicting `_ramfs` flags. |
| kb.CreateCustomKernel( |
| KERNEL_FLAGS, |
| [ |
| x |
| for x in os.environ.get("USE", "").split() |
| if not x.endswith("_ramfs") |
| ], |
| ) |
| kernel = os.path.join(work_dir, MINIOS_KERNEL_IMAGE) |
| assert " " not in version, f"bad version: {version}" |
| boot_args = f"noinitrd panic=60 cros_minios_version={version} cros_minios" |
| if developer_mode: |
| boot_args += f" {CROS_DEBUG_FLAG}" |
| kb.CreateKernelImage( |
| kernel, |
| boot_args=boot_args, |
| serial=serial, |
| keys_dir=keys_dir, |
| public_key=public_key, |
| private_key=private_key, |
| keyblock=keyblock, |
| ) |
| return kernel |
| |
| |
| def InsertMiniOsKernelImage(image: str, kernel: str) -> None: |
| """Writes miniOS kernel into A + B miniOS partitions of the image. |
| |
| A + B partitions of miniOS need to have enough space allocated for each copy |
| of the miniOS kernel to fit into. |
| |
| Args: |
| image: The path to the Chromium OS image. |
| kernel: The path to the kernel image. |
| """ |
| with image_lib.LoopbackPartitions(image) as devs: |
| for part_name in (constants.PART_MINIOS_A, constants.PART_MINIOS_B): |
| part_info = devs.GetPartitionInfo(part_name) |
| kernel_size = os.path.getsize(kernel) |
| if kernel_size > part_info.size: |
| raise MiniOsError( |
| f"MiniOS kernel is larger than the {part_name} partition." |
| ) |
| |
| device = devs.GetPartitionDevName(part_name) |
| logging.debug("MiniOS loopback partition is %s", device) |
| |
| logging.info( |
| "Writing the MiniOS kernel %s into image %s at %s", |
| kernel, |
| image, |
| device, |
| ) |
| |
| kernel_blocks = kernel_size // BLOCK_SIZE |
| part_blocks = part_info.size // BLOCK_SIZE |
| |
| # First zero out partition. |
| # This generally would help with update payloads so we don't have |
| # to compress junk bytes. The target file is a loopback dev device |
| # of a miniOS partition. |
| cros_build_lib.sudo_run( |
| [ |
| "dd", |
| "if=/dev/zero", |
| f"of={device}", |
| f"bs={BLOCK_SIZE}", |
| f"seek={kernel_blocks}", |
| f"count={part_blocks - kernel_blocks}", |
| ] |
| ) |
| # Write the actual MiniOS kernel into the A + B partitions. |
| cros_build_lib.sudo_run( |
| ["dd", f"if={kernel}", f"of={device}", f"bs={BLOCK_SIZE}"] |
| ) |