xref: /aosp_15_r20/external/coreboot/util/chromeos/crosfirmware.sh (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1#!/usr/bin/env bash
2#
3# SPDX-License-Identifier: GPL-2.0-only
4
5# On some systems, `parted` and `debugfs` are located in /sbin.
6export PATH="$PATH:/sbin"
7
8exit_if_uninstalled() {
9	local cmd_name="$1"
10	local deb_pkg_name="$2"
11
12	if type "$cmd_name" >/dev/null 2>&1; then
13		return
14	fi
15
16	printf '`%s` was not found. ' "$cmd_name" >&2
17	printf 'On Debian-based systems, it can be installed\n' >&2
18	printf 'by running `apt install %s`.\n' "$deb_pkg_name" >&2
19
20	exit 1
21}
22
23exit_if_dependencies_are_missing() {
24	exit_if_uninstalled "uudecode" "sharutils"
25	exit_if_uninstalled "debugfs" "e2fsprogs"
26	exit_if_uninstalled "parted" "parted"
27	exit_if_uninstalled "curl" "curl"
28	exit_if_uninstalled "unzip" "unzip"
29}
30
31get_inventory() {
32	_conf=$1
33	_url=https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.conf
34
35	echo "Downloading recovery image inventory..."
36
37	curl -s "$_url" >$_conf
38}
39
40download_image() {
41	_url=$1
42	_file=$2
43
44	echo "Downloading recovery image"
45	curl "$_url" >"$_file.zip"
46	echo "Decompressing recovery image"
47	unzip -q "$_file.zip"
48	rm "$_file.zip"
49}
50
51extract_partition() {
52	NAME=$1
53	FILE=$2
54	ROOTFS=$3
55	_bs=1024
56
57	echo "Extracting ROOT-A partition"
58	ROOTP=$(printf "unit\nB\nprint\nquit\n" |
59		parted $FILE 2>/dev/null | grep $NAME)
60
61	if [ "$ROOTP" == "" ]; then
62		# Automatic extraction failed, likely due to parted detecting
63		# overlapping partitions. Fall back to using fdisk and assume
64		# ROOT-A is partition #3
65		echo "(Extracting via parted failed; falling back to fdisk)"
66		_ssize=$(printf "p q" | fdisk $FILE | grep "Sector size" |
67			cut -f2 -d: | cut -f2 -d ' ')
68		_start=$(printf "p q" | fdisk $FILE | grep "bin3" | tr -s ' ' |
69			cut -f2 -d ' ')
70		_nsec=$(printf "p q" | fdisk $FILE | grep "bin3" | tr -s ' ' |
71			cut -f4 -d ' ')
72		START=$(($_ssize * $_start))
73		SIZE=$(($_ssize * $_nsec))
74	else
75		START=$(($(echo $ROOTP | cut -f2 -d\  | tr -d "B")))
76		SIZE=$(($(echo $ROOTP | cut -f4 -d\  | tr -d "B")))
77	fi
78
79	dd if=$FILE of=$ROOTFS bs=$_bs skip=$(($START / $_bs)) \
80		count=$(($SIZE / $_bs)) >/dev/null 2>&1
81}
82
83extract_shellball() {
84	ROOTFS=$1
85	SHELLBALL=$2
86
87	echo "Extracting chromeos-firmwareupdate"
88	printf "cd /usr/sbin\ndump chromeos-firmwareupdate $SHELLBALL\nquit" |
89		debugfs $ROOTFS >/dev/null 2>&1
90}
91
92extract_coreboot() {
93	_shellball=$1
94	_unpacked=$(mktemp -d)
95
96	echo "Extracting coreboot image"
97	if ! sh $_shellball --unpack $_unpacked >/dev/null 2>&1; then
98		sh $_shellball --sb_extract $_unpacked >/dev/null 2>&1
99	fi
100
101	if [ -d $_unpacked/models/ ]; then
102		_version=$(cat $_unpacked/VERSION | grep -m 1 -e Model.*$_board -A5 |
103			grep "BIOS (RW) version:" | cut -f2 -d: | tr -d \ )
104		if [ "$_version" == "" ]; then
105			_version=$(cat $_unpacked/VERSION | grep -m 1 -e Model.*$_board -A5 |
106				grep "BIOS version:" | cut -f2 -d: | tr -d \ )
107		fi
108		_bios_image=$(grep "IMAGE_MAIN" $_unpacked/models/$_board/setvars.sh |
109			cut -f2 -d\")
110	else
111		_version=$(cat $_unpacked/VERSION | grep BIOS\ version: |
112			cut -f2 -d: | tr -d \ )
113		_bios_image=bios.bin
114	fi
115	if cp $_unpacked/$_bios_image coreboot-$_version.bin; then
116		echo "Extracted coreboot-$_version.bin"
117	fi
118	rm -rf "$_unpacked"
119	rm $_shellball
120}
121
122do_one_board() {
123	_board=$1
124	_url=$2
125	_file=$3
126
127	download_image $_url $_file
128
129	extract_partition ROOT-A $_file root-a.ext2
130	extract_shellball root-a.ext2 chromeos-firmwareupdate-$_board
131	rm $_file root-a.ext2
132
133	extract_coreboot chromeos-firmwareupdate-$_board
134}
135
136#
137# Main
138#
139
140BOARD=${1,,}
141
142exit_if_dependencies_are_missing
143
144if [ "$BOARD" == "all" ]; then
145	CONF=$(mktemp)
146	get_inventory $CONF
147
148	grep ^name= $CONF | while read _line; do
149		name=$(echo $_line | cut -f2 -d=)
150		echo Processing board $name
151		eval $(grep -v hwid= $CONF | grep -A11 "$_line" |
152			grep '\(url=\|file=\)')
153		BOARD=$(echo $url | cut -f3 -d_)
154		do_one_board $BOARD $url $file
155	done
156
157	rm "$CONF"
158elif [ "$BOARD" != "" ]; then
159	CONF=$(mktemp)
160	get_inventory $CONF
161
162	echo Processing board $BOARD
163	eval $(grep -i $BOARD -A8 $CONF | grep '\(url=\|file=\)')
164	do_one_board $BOARD $url $file
165
166	rm "$CONF"
167else
168	echo "Usage: $0 <boardname>"
169	echo "       $0 all"
170	echo
171	exit 1
172fi
173