blob: b2fa4fc9de12c1822aae8b9106bd23963ac519d1 [file] [log] [blame]
Hung-Te Lin3bdfc462010-10-15 02:17:02 +08001#!/bin/sh
2#
Gaurav Shah605500b2011-01-18 12:00:50 -08003# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Hung-Te Lin3bdfc462010-10-15 02:17:02 +08004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6#
7# This script can change key (usually developer keys) in a firmware binary
Hung-Te Lin20525b92010-10-16 09:37:32 +08008# image or system live firmware (EEPROM), and assign proper HWID, BMPFV as well.
Hung-Te Lin3bdfc462010-10-15 02:17:02 +08009
10SCRIPT_BASE="$(dirname "$0")"
Gaurav Shah605500b2011-01-18 12:00:50 -080011. "$SCRIPT_BASE/common_minimal.sh"
Hung-Te Lin20525b92010-10-16 09:37:32 +080012load_shflags || exit 1
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080013
14# Constants used by DEFINE_*
Hung-Te Lin20525b92010-10-16 09:37:32 +080015VBOOT_BASE='/usr/share/vboot'
16DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys"
Hung-Te Linf82f4ae2011-03-04 09:04:36 +080017DEFAULT_BMPFV_FILE="<auto>"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080018DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups'
Hung-Te Linf82f4ae2011-03-04 09:04:36 +080019DEFAULT_FIRMWARE_UPDATER='/usr/sbin/chromeos-firmwareupdate'
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080020
21# DEFINE_string name default_value description flag
22DEFINE_string from "" "Path of input file (empty for system live firmware)" "f"
23DEFINE_string to "" "Path of output file (empty for system live firmware)" "t"
Hung-Te Lin20525b92010-10-16 09:37:32 +080024DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k"
Hung-Te Linf82f4ae2011-03-04 09:04:36 +080025DEFINE_string bmpfv "$DEFAULT_BMPFV_FILE" \
26 "Path to the new bitmaps, <auto> to extract from system, empty to keep." ""
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080027DEFINE_boolean force_backup \
28 $FLAGS_TRUE "Create backup even if source is not live" ""
29DEFINE_string backup_dir \
30 "$DEFAULT_BACKUP_FOLDER" "Path of directory to store firmware backups" ""
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080031
32# Parse command line
33FLAGS "$@" || exit 1
34eval set -- "$FLAGS_ARGV"
35
36# Globals
37# ----------------------------------------------------------------------------
38set -e
39
40# the image we are (temporary) working with
Hung-Te Lin20525b92010-10-16 09:37:32 +080041IMAGE="$(make_temp_file)"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080042
43# a log file to keep the output results of executed command
Hung-Te Lin20525b92010-10-16 09:37:32 +080044EXEC_LOG="$(make_temp_file)"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080045
46# Functions
47# ----------------------------------------------------------------------------
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080048
Hung-Te Lin38d3ef72011-01-06 09:59:35 +080049# Disables write protection status registers
50disable_write_protection() {
51 # No need to change WP status in file mode
52 if [ -n "$FLAGS_to" ]; then
53 return $FLAGS_TRUE
54 fi
55
56 # --wp-disable command may return success even if WP is still enabled,
57 # so we should use --wp-status to verify the results.
58 echo "Disabling system software write protection status..."
59 (flashrom --wp-disable && flashrom --wp-status) 2>&1 |
60 tee "$EXEC_LOG" |
61 grep -q '^WP: .* is disabled\.$'
62}
63
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080064# Reads $IMAGE from $FLAGS_from
65read_image() {
66 if [ -z "$FLAGS_from" ]; then
67 echo "Reading system live firmware..."
68 if is_debug_mode; then
69 flashrom -V -r "$IMAGE"
70 else
71 flashrom -r "$IMAGE" >"$EXEC_LOG" 2>&1
72 fi
73 else
74 debug_msg "reading from file: $FLAGS_from"
75 cp -f "$FLAGS_from" "$IMAGE"
76 fi
77}
78
79# Writes $IMAGE to $FLAGS_to
80write_image() {
81 if [ -z "$FLAGS_to" ]; then
82 echo "Writing system live firmware..."
Hung-Te Lin20525b92010-10-16 09:37:32 +080083 # TODO(hungte) we can enable partial write to make this faster
Hung-Te Lin3bdfc462010-10-15 02:17:02 +080084 if is_debug_mode; then
85 flashrom -V -w "$IMAGE"
86 else
87 flashrom -w "$IMAGE" >"$EXEC_LOG" 2>&1
88 fi
89 else
90 debug_msg "writing to file: $FLAGS_to"
91 cp -f "$IMAGE" "$FLAGS_to"
92 chmod a+r "$FLAGS_to"
93 fi
94}
95
96# Converts HWID from $1 to proper format with "DEV" extension
97echo_dev_hwid() {
98 local hwid="$1"
99 local hwid_no_dev="${hwid% DEV}"
100
101 # NOTE: Some DEV firmware image files may put GUID in HWID.
102 # These are not officially supported and they will see "{GUID} DEV".
Hung-Te Lin20525b92010-10-16 09:37:32 +0800103 # Also there's some length limitation in chromeos_acpi/HWID, so
104 # a "{GUID} DEV" will become "{GUID} " in that case.
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800105
106 if [ "$hwid" != "$hwid_no_dev" ]; then
107 hwid="$hwid_no_dev"
108 fi
109 local hwid_dev="$hwid DEV"
110 debug_msg "echo_dev_hwid: [$1] -> [$hwid_dev]"
111 echo "$hwid_dev"
112}
113
Hung-Te Linf82f4ae2011-03-04 09:04:36 +0800114# Explores compatible firmware bitmaps
115explore_bmpfv() {
116 local tmp_folder=""
117
118 if [ -s "$DEFAULT_FIRMWARE_UPDATER" ]; then
119 # try to extract from built-in firmware updater
120 debug_msg "found default firmware updater, trying to fetch bitmap..."
121 tmp_folder=$("$DEFAULT_FIRMWARE_UPDATER" --sb_extract | sed "s'[^/]*''")
122 debug_msg "updater resources extrated to: $tmp_folder"
123
124 if [ -d "$tmp_folder" -a -s "$tmp_folder/bios.bin" ]; then
125 new_bmpfv="$tmp_folder/bmpfv.bin"
126 echo "$new_bmpfv"
127 gbb_utility --bmpfv="$new_bmpfv" "$tmp_folder/bios.bin" >/dev/null 2>&1
128 else
129 debug_msg "failed to find valid BIOS image file."
130 fi
131 else
132 debug_msg "no firmware updater in system. not changing bitmaps."
133 fi
134}
135
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800136# Main
137# ----------------------------------------------------------------------------
138main() {
139 # Check parameters
140 local root_pubkey="$FLAGS_keys/root_key.vbpubk"
141 local recovery_pubkey="$FLAGS_keys/recovery_key.vbpubk"
142 local firmware_keyblock="$FLAGS_keys/firmware.keyblock"
143 local firmware_prvkey="$FLAGS_keys/firmware_data_key.vbprivk"
Hung-Te Lin2c7213d2011-03-24 01:35:33 +0800144 local dev_firmware_keyblock="$FLAGS_keys/dev_firmware.keyblock"
145 local dev_firmware_prvkey="$FLAGS_keys/dev_firmware_data_key.vbprivk"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800146 local kernel_sub_pubkey="$FLAGS_keys/kernel_subkey.vbpubk"
147 local new_bmpfv="$FLAGS_bmpfv"
148 local is_from_live=0
149 local backup_image=
Hung-Te Linf82f4ae2011-03-04 09:04:36 +0800150 local opt_bmpfv=""
151
152 if [ "$new_bmpfv" = "$DEFAULT_BMPFV_FILE" ]; then
153 new_bmpfv=$(explore_bmpfv) &&
154 debug_msg "Using bitmaps from $new_bmpfv"
155 fi
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800156
Hung-Te Lin20525b92010-10-16 09:37:32 +0800157 debug_msg "Prerequisite check"
158 ensure_files_exist \
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800159 "$root_pubkey" \
160 "$recovery_pubkey" \
161 "$firmware_keyblock" \
162 "$firmware_prvkey" \
Hung-Te Linf82f4ae2011-03-04 09:04:36 +0800163 "$kernel_sub_pubkey" ||
Hung-Te Lin20525b92010-10-16 09:37:32 +0800164 exit 1
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800165
Hung-Te Linf82f4ae2011-03-04 09:04:36 +0800166 if [ -n "$new_bmpfv" ]; then
167 opt_bmpfv="--bmpfv=$new_bmpfv"
168 ensure_files_exist "$new_bmpfv" || exit 1
169 fi
170
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800171 if [ -z "$FLAGS_from" ]; then
172 is_from_live=1
173 else
Hung-Te Linf82f4ae2011-03-04 09:04:36 +0800174 ensure_files_exist "$FLAGS_from" || exit 1
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800175 fi
176
Hung-Te Lin38d3ef72011-01-06 09:59:35 +0800177 debug_msg "Checking software write protection status"
178 disable_write_protection ||
179 if is_debug_mode; then
180 err_die "Failed to disable WP. Diagnose Message: $(cat "$EXEC_LOG")"
181 else
182 err_die "Write protection is still enabled. " \
183 "Please verify that hardware write protection is disabled."
184 fi
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800185
186 debug_msg "Pulling image to $IMAGE"
187 (read_image && [ -s "$IMAGE" ]) ||
188 err_die "Failed to read image. Error message: $(cat "$EXEC_LOG")"
189
190 debug_msg "Prepare to backup the file"
191 if [ -n "$is_from_live" -o $FLAGS_force_backup = $FLAGS_TRUE ]; then
Hung-Te Lin20525b92010-10-16 09:37:32 +0800192 backup_image="$(make_temp_file)"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800193 debug_msg "Creating backup file to $backup_image..."
194 cp -f "$IMAGE" "$backup_image"
195 fi
196
197 # TODO(hungte) We can use vbutil_firmware to check if the current firmware is
Hung-Te Lin20525b92010-10-16 09:37:32 +0800198 # valid so that we know keys and vbutil_firmware are all working fine.
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800199
200 echo "Preparing new firmware image..."
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800201 debug_msg "Extract current HWID and rootkey"
202 local old_hwid
Hung-Te Lin20525b92010-10-16 09:37:32 +0800203 old_hwid="$(gbb_utility --get --hwid "$IMAGE" 2>"$EXEC_LOG" |
204 grep '^hardware_id:' |
205 sed 's/^hardware_id: //')"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800206
207 debug_msg "Decide new HWID"
208 if [ -z "$old_hwid" ]; then
209 err_die "Cannot find current HWID. (message: $(cat "$EXEC_LOG"))"
210 fi
Hung-Te Lin20525b92010-10-16 09:37:32 +0800211 local new_hwid="$(echo_dev_hwid "$old_hwid")"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800212
213 debug_msg "Replace GBB parts (gbb_utility allows changing on-the-fly)"
214 gbb_utility --set \
215 --hwid="$new_hwid" \
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800216 --rootkey="$root_pubkey" \
217 --recoverykey="$recovery_pubkey" \
Hung-Te Linf82f4ae2011-03-04 09:04:36 +0800218 $opt_bmpfv \
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800219 "$IMAGE" >"$EXEC_LOG" 2>&1 ||
220 err_die "Failed to change GBB Data. (message: $(cat "$EXEC_LOG"))"
221
222 debug_msg "Resign the firmware code (A/B) with new keys"
Hung-Te Lin20525b92010-10-16 09:37:32 +0800223 local unsigned_image="$(make_temp_file)"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800224 cp -f "$IMAGE" "$unsigned_image"
Hung-Te Lin8e17e5f2011-07-22 16:07:58 +0800225 # TODO(hungte) derive kernel key and preamble flag from existing firmware
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800226 "$SCRIPT_BASE/resign_firmwarefd.sh" \
227 "$unsigned_image" \
228 "$IMAGE" \
229 "$firmware_prvkey" \
230 "$firmware_keyblock" \
Hung-Te Lin2c7213d2011-03-24 01:35:33 +0800231 "$dev_firmware_prvkey" \
232 "$dev_firmware_keyblock" \
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800233 "$kernel_sub_pubkey" >"$EXEC_LOG" 2>&1 ||
234 err_die "Failed to re-sign firmware. (message: $(cat "$EXEC_LOG"))"
Hung-Te Lin8e17e5f2011-07-22 16:07:58 +0800235 if is_debug_mode; then
236 cat "$EXEC_LOG"
237 fi
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800238
239 # TODO(hungte) compare if the image really needs to be changed.
240
Hung-Te Lin20525b92010-10-16 09:37:32 +0800241 debug_msg "Check if we need to make backup file(s)"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800242 if [ -n "$backup_image" ]; then
Hung-Te Lin20525b92010-10-16 09:37:32 +0800243 local backup_hwid_name="$(echo "$old_hwid" | sed 's/ /_/g')"
244 local backup_date_time="$(date +'%Y%m%d_%H%M%S')"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800245 local backup_file_name="firmware_${backup_hwid_name}_${backup_date_time}.fd"
246 local backup_file_path="$FLAGS_backup_dir/$backup_file_name"
247 if mkdir -p "$FLAGS_backup_dir" &&
248 cp -f "$backup_image" "$backup_file_path"; then
Hung-Te Lineb868ee2010-10-19 11:08:24 +0800249 true
250 elif cp -f "$backup_image" "/tmp/$backup_file_name"; then
251 backup_file_path="/tmp/$backup_file_name"
252 else
253 backup_file_path=''
254 fi
255 if [ -n "$backup_file_path" -a -s "$backup_file_path" ]; then
256 # TODO(hungte) maybe we can wrap the flashrom by 'make_dev_firmware.sh -r'
257 # so that the only command to remember would be make_dev_firmware.sh.
258 echo "
259 Backup of current firmware image is stored in:
260 $backup_file_path
261 Please copy the backup file to a safe place ASAP.
262
263 To stop using devkeys and restore original firmware, execute command:
264 flashrom -w [PATH_TO_BACKUP_IMAGE]
265 Ex: flashrom -w $backup_file_path
266 "
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800267 else
Hung-Te Lin20525b92010-10-16 09:37:32 +0800268 echo "WARNING: Cannot create file in $FLAGS_backup_dir... Ignore backups."
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800269 fi
270 fi
271
272 # TODO(hungte) use vbutil_firmware to check if the new firmware is valid.
Hung-Te Lin20525b92010-10-16 09:37:32 +0800273 # Or, do verification in resign_firmwarefd.sh and trust it.
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800274
275 debug_msg "Write the image"
276 write_image ||
277 err_die "Failed to write image. Error message: $(cat "$EXEC_LOG")"
278
279 debug_msg "Complete."
280 if [ -z "$FLAGS_to" ]; then
281 echo "Successfully changed firmware to Developer Keys. New HWID: $new_hwid"
282 else
Hung-Te Lin20525b92010-10-16 09:37:32 +0800283 echo "Firmware '$FLAGS_to' now uses Developer Keys. New HWID: $new_hwid"
Hung-Te Lin3bdfc462010-10-15 02:17:02 +0800284 fi
285}
286
287main