| #!/bin/bash |
| set -o errexit |
| set -o pipefail |
| set -o nounset |
| |
| # Script to generate kernelefi.img and shimefi.img. |
| # |
| # kernelefi.img uses a kernel from cos-125-19216-104-133 and shimefi.img uses a |
| # shim from the same COS image. |
| # |
| # e.g.: |
| # bash create_efi_gpt.sh kernelefi.img bzImage 2 /efi/boot/bootx64.efi |
| # bash create_efi_gpt.sh shimefi.img shimx64.efi 2 /efi/boot/bootx64.efi |
| |
| if [[ $# -ne 4 ]]; then |
| echo "Usage: $0 <output_image_path> <bootx64_efi_source> <priority_partition> <efi_internal_path>" |
| echo "Example efi_internal_path: /efi/boot/bootx64.efi" |
| exit 1 |
| fi |
| |
| readonly OUTPUT_IMAGE="$1" |
| readonly BOOT_SOURCE="$2" |
| readonly PRIORITY_PART="$3" |
| readonly EFI_INTERNAL_PATH="$4" |
| readonly EFI_PART_IMAGE="efi_part.img" |
| |
| # 1. Calculate required size for the partition |
| SOURCE_SIZE=$(stat -c%s "$BOOT_SOURCE") |
| # Add overhead for FAT metadata (at least 512KB for small files, total min 1MB) |
| EFI_SIZE_BYTES=$((SOURCE_SIZE + 512 * 1024)) |
| if [[ $EFI_SIZE_BYTES -lt $((1024 * 1024)) ]]; then |
| EFI_SIZE_BYTES=$((1024 * 1024)) |
| fi |
| # Align partition size to 512-byte sectors |
| PART_SIZE_SECTORS=$(( (EFI_SIZE_BYTES + 511) / 512 )) |
| |
| # 2. Create the FAT image |
| truncate -s "$((PART_SIZE_SECTORS * 512))" "$EFI_PART_IMAGE" |
| mkfs.vfat "$EFI_PART_IMAGE" |
| |
| # 3. Create directory structure and copy the EFI file |
| # Ensure leading ::/ for mtools |
| INTERNAL_PATH_MTOOLS="::${EFI_INTERNAL_PATH#/}" |
| DIR_PATH=$(dirname "${EFI_INTERNAL_PATH}") |
| |
| # Recursively create directories |
| IFS='/' read -ra ADDR <<< "$DIR_PATH" |
| CURRENT_DIR="::" |
| for i in "${ADDR[@]}"; do |
| if [[ -n "$i" ]]; then |
| CURRENT_DIR="${CURRENT_DIR}/$i" |
| # mmd might fail if directory exists, so we ignore error. |
| mmd -i "$EFI_PART_IMAGE" "$CURRENT_DIR" || true |
| fi |
| done |
| |
| mcopy -i "$EFI_PART_IMAGE" "$BOOT_SOURCE" "$INTERNAL_PATH_MTOOLS" |
| |
| # 4. Define GPT layout |
| # Start at sector 2048 (1MiB) for alignment compatibility and to avoid |
| # "sector already used" errors with some versions of sfdisk. |
| readonly START_SECTOR=2048 |
| # Backup GPT is 33 sectors at the end. |
| # sfdisk by default aligns partitions to 1MiB (2048 sectors). |
| # We add enough sectors to account for alignment of partitions 2, 3, and 4. |
| TOTAL_SECTORS=$(( START_SECTOR + PART_SIZE_SECTORS + 3 * 2048 + 33 )) |
| |
| # 5. Create the final container |
| truncate -s "$((TOTAL_SECTORS * 512))" "$OUTPUT_IMAGE" |
| |
| # 6. Initialize GPT and create the partitions |
| # Partition 1: EFI System Partition GUID: C12A7328-F81F-11D2-BA4B-00A0C93EC93B |
| # Partition 2: ChromeOS Kernel GUID: FE3A2A5D-4F32-41A7-B725-ACCC3285A309 |
| # Partition 3: ChromeOS Root GUID: 3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC |
| # Partition 4: ChromeOS Kernel GUID: FE3A2A5D-4F32-41A7-B725-ACCC3285A309 |
| echo "label: gpt |
| start=${START_SECTOR}, size=${PART_SIZE_SECTORS}, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name=\"EFI-SYSTEM\" |
| size=1, type=FE3A2A5D-4F32-41A7-B725-ACCC3285A309, name=\"KERN-A\" |
| size=1, type=3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC, name=\"ROOT-A\" |
| size=1, type=FE3A2A5D-4F32-41A7-B725-ACCC3285A309, name=\"KERN-B\"" | sfdisk --no-reread "$OUTPUT_IMAGE" |
| |
| cgpt prioritize -i "$PRIORITY_PART" -P 2 "$OUTPUT_IMAGE" |
| |
| # 7. DD the EFI partition into the GPT image |
| dd if="$EFI_PART_IMAGE" of="$OUTPUT_IMAGE" bs=512 seek="${START_SECTOR}" conv=notrunc status=none |
| |
| # Cleanup |
| rm "$EFI_PART_IMAGE" |
| |
| echo "Successfully created minimal GPT image: $OUTPUT_IMAGE ($((TOTAL_SECTORS * 512 / 1024)) KiB)" |