From aceca1c085bc8af0d5d7eb0a986ec30540dc88d1 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Fri, 13 May 2011 22:09:04 +0800 Subject: [PATCH] crosutils: add a script to merge shim-type images The design of Chromium OS disk image allows trying to boot with multiple partitions. This script can merge images with different kernels (even signed with different keys) into one single image. Useful for factory process which usually needs to deal with DEV/PVT/MP signed shims. BUG=chrome-os-partner:2888 TEST=./merge_shim_image.sh mp.bin pvt.bin # output image works for both PVT/MP devices Change-Id: I21d267bc74fab2d581ccbd0818160407aff35467 Reviewed-on: http://gerrit.chromium.org/gerrit/847 Reviewed-by: Nick Sanders Tested-by: Hung-Te Lin --- merge_shim_image.sh | 165 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100755 merge_shim_image.sh diff --git a/merge_shim_image.sh b/merge_shim_image.sh new file mode 100755 index 0000000000..8ba29d30fd --- /dev/null +++ b/merge_shim_image.sh @@ -0,0 +1,165 @@ +#!/bin/sh +# +# Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +SCRIPT="$0" +set -e + +# CGPT Header: PMBR, header, table; sec_table, sec_header +CGPT_START_SIZE=$((1 + 1 + 32)) +CGPT_END_SIZE=$((32 + 1)) +CGPT_BS="512" + +STATE_PARTITION="1" +LEGACY_PARTITIONS="8 9 10 11 12" +RESERVED_PARTITION="9" + +die() { + echo "ERROR: $*" >&2 + exit 1 +} + +# TODO(hungte) support parted if cgpt is not available +image_get_partition_offset() { + cgpt show -n -i "$2" -b "$1" +} + +image_get_partition_size() { + cgpt show -n -i "$2" -s "$1" +} + +image_get_partition_type() { + cgpt show -n -i "$2" -t "$1" +} + +image_get_partition_label() { + cgpt show -n -i "$2" -l "$1" +} + +image_enable_kernel() { + cgpt add -P 1 -S 1 -i "$2" "$1" +} + +image_copy_partition() { + local from_image="$1" + local from_part="$2" + local to_image="$3" + local to_part="$4" + + local from_offset="$(image_get_partition_offset "$from_image" "$from_part")" + local from_size="$(image_get_partition_size "$from_image" "$from_part")" + local to_offset="$(image_get_partition_offset "$to_image" "$to_part")" + local to_size="$(image_get_partition_size "$to_image" "$to_part")" + + if [ "$from_size" -ne "$to_size" ]; then + die "Failed to copy partition: $from_image#$from_part -> $to_image#$to_part" + fi + + # TODO(hungte) Speed up by increasing bs + dd if="$from_image" of="$to_image" bs="$CGPT_BS" conv=notrunc \ + count=$from_size skip="$from_offset" seek="$to_offset" +} + +images_get_total_size() { + local image="" + local total="0" + local index + + # copy most partitions from first image + total="$((total + CGPT_START_SIZE + CGPT_END_SIZE))" + for index in $STATE_PARTITION $LEGACY_PARTITIONS; do + total="$((total + $(image_get_partition_size "$1" $index) ))" + done + + for image in "$1" "$2" "$3"; do + if [ -z "$image" ]; then + total="$((total + $(image_get_partition_size "$1" $RESERVED_PARTITION)))" + total="$((total + $(image_get_partition_size "$1" $RESERVED_PARTITION)))" + continue + fi + total="$((total + $(image_get_partition_size "$image" 2)))" + total="$((total + $(image_get_partition_size "$image" 3)))" + done + echo "$total" +} + +image_append_partition() { + local from_image="$1" + local to_image="$2" + local from_part="$3" + local last_part="$(cgpt show "$to_image" | grep Label | wc -l)" + local to_part="$((last_part + 1))" + echo "image_append_partition: $from_image#$from_part -> $to_image#$to_part" + + local guid="$(image_get_partition_type "$from_image" "$from_part")" + local size="$(image_get_partition_size "$from_image" "$from_part")" + local label="$(image_get_partition_label "$from_image" "$from_part")" + local offset="$CGPT_START_SIZE" + + if [ "$last_part" -gt 0 ]; then + offset="$(( $(image_get_partition_offset "$to_image" "$last_part") + + $(image_get_partition_size "$to_image" "$last_part") ))" + fi + + echo cgpt add "$to_image" -t "$guid" -b "$offset" -s "$size" -l "$label" + cgpt add "$to_image" -t "$guid" -b "$offset" -s "$size" -l "$label" + image_copy_partition "$from_image" "$from_part" "$to_image" "$to_part" +} + +main() { + local force="" + if [ "$1" = "-f" ]; then + shift + force="True" + fi + if [ "$#" -lt 2 -o "$#" -gt 4 ]; then + echo "Usage: $SCRIPT [-f] output shim_image_1 [shim_2 [shim_3]]" + exit 1 + fi + + local image="" + local output="$1" + local main_source="$2" + local index="" + local slots="0" + shift + + if [ -f "$output" -a -z "$force" ]; then + die "Output file $output already exists. To overwrite the file, add -f." + fi + for image in "$@"; do + if [ ! -f "$image" ]; then + die "Cannot find input file $image." + fi + done + + # build output + local total_size="$(images_get_total_size "$@")" + # echo "Total size from [$@]: $total_size" + truncate "$output" -s "$((total_size * CGPT_BS))" + cgpt create "$output" + cgpt boot -p "$output" + + # copy most partitions from first image + image_append_partition "$main_source" "$output" $STATE_PARTITION + local kpart=2 + local rootfs_part=3 + for image in "$1" "$2" "$3"; do + if [ -z "$image" ]; then + image="$1" + kpart="$RESERVED_PARTITION" + rootfs_part="$RESERVED_PARTITION" + fi + image_append_partition "$image" "$output" "$kpart" + image_append_partition "$image" "$output" "$rootfs_part" + slots="$((slots + 1))" + image_enable_kernel "$output" "$((slots * 2))" + done + for index in $LEGACY_PARTITIONS; do + image_append_partition "$main_source" "$output" "$index" + done +} + +main "$@"