blob: e8903db2a7c812248f087bddc2e007e29f4b0acd [file] [log] [blame]
#!/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 to generate an universal factory install shim image, by merging
# multiple images signed by different keys.
# CAUTION: Recovery shim images are not supported yet because they require the
# kernel partitions to be laid out in a special way
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 "$@"