1*4f2df630SAndroid Build Coastguard Worker /*
2*4f2df630SAndroid Build Coastguard Worker * Copyright 2015 The ChromiumOS Authors
3*4f2df630SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
4*4f2df630SAndroid Build Coastguard Worker * found in the LICENSE file.
5*4f2df630SAndroid Build Coastguard Worker */
6*4f2df630SAndroid Build Coastguard Worker
7*4f2df630SAndroid Build Coastguard Worker #include <asm/byteorder.h>
8*4f2df630SAndroid Build Coastguard Worker #include <ctype.h>
9*4f2df630SAndroid Build Coastguard Worker #include <endian.h>
10*4f2df630SAndroid Build Coastguard Worker #include <errno.h>
11*4f2df630SAndroid Build Coastguard Worker #include <fcntl.h>
12*4f2df630SAndroid Build Coastguard Worker #include <getopt.h>
13*4f2df630SAndroid Build Coastguard Worker #include <libusb.h>
14*4f2df630SAndroid Build Coastguard Worker #include <openssl/evp.h>
15*4f2df630SAndroid Build Coastguard Worker #include <openssl/sha.h>
16*4f2df630SAndroid Build Coastguard Worker #include <stdarg.h>
17*4f2df630SAndroid Build Coastguard Worker #include <stdbool.h>
18*4f2df630SAndroid Build Coastguard Worker #include <stdint.h>
19*4f2df630SAndroid Build Coastguard Worker #include <stdio.h>
20*4f2df630SAndroid Build Coastguard Worker #include <stdlib.h>
21*4f2df630SAndroid Build Coastguard Worker #include <string.h>
22*4f2df630SAndroid Build Coastguard Worker #include <sys/stat.h>
23*4f2df630SAndroid Build Coastguard Worker #include <sys/types.h>
24*4f2df630SAndroid Build Coastguard Worker #include <termios.h>
25*4f2df630SAndroid Build Coastguard Worker #include <unistd.h>
26*4f2df630SAndroid Build Coastguard Worker
27*4f2df630SAndroid Build Coastguard Worker #include "config.h"
28*4f2df630SAndroid Build Coastguard Worker
29*4f2df630SAndroid Build Coastguard Worker #include "ap_ro_integrity_check.h"
30*4f2df630SAndroid Build Coastguard Worker #include "ccd_config.h"
31*4f2df630SAndroid Build Coastguard Worker #include "compile_time_macros.h"
32*4f2df630SAndroid Build Coastguard Worker #include "dauntless_event.h"
33*4f2df630SAndroid Build Coastguard Worker #include "flash_log.h"
34*4f2df630SAndroid Build Coastguard Worker #include "generated_version.h"
35*4f2df630SAndroid Build Coastguard Worker #include "gsctool.h"
36*4f2df630SAndroid Build Coastguard Worker #include "misc_util.h"
37*4f2df630SAndroid Build Coastguard Worker #include "signed_header.h"
38*4f2df630SAndroid Build Coastguard Worker #include "signed_manifest.h"
39*4f2df630SAndroid Build Coastguard Worker #include "tpm_registers.h"
40*4f2df630SAndroid Build Coastguard Worker #include "tpm_vendor_cmds.h"
41*4f2df630SAndroid Build Coastguard Worker #include "upgrade_fw.h"
42*4f2df630SAndroid Build Coastguard Worker #include "u2f.h"
43*4f2df630SAndroid Build Coastguard Worker #include "usb_descriptor.h"
44*4f2df630SAndroid Build Coastguard Worker #include "verify_ro.h"
45*4f2df630SAndroid Build Coastguard Worker
46*4f2df630SAndroid Build Coastguard Worker /*
47*4f2df630SAndroid Build Coastguard Worker * This enum must match CcdCap enum in applications/sys_mgr/src/ccd.rs in the
48*4f2df630SAndroid Build Coastguard Worker * Ti50 common git tree.
49*4f2df630SAndroid Build Coastguard Worker */
50*4f2df630SAndroid Build Coastguard Worker enum Ti50CcdCapabilities {
51*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UART_GSC_RX_AP_TX = 0,
52*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UART_GSC_TX_AP_RX,
53*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UART_GSC_RX_EC_TX,
54*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UART_GSC_TX_EC_RX,
55*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UART_GSC_RX_FPMCU_TX,
56*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UART_GSC_TX_FPMCU_RX,
57*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_FLASH_AP,
58*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_FLASH_EC,
59*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_OVERRIDE_WP,
60*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_REBOOT_ECAP,
61*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_GSC_FULL_CONSOLE,
62*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UNLOCK_NO_REBOOT,
63*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_UNLOCK_NO_SHORT_PP,
64*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_OPEN_NO_TPM_WIPE,
65*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_OPEN_NO_LONG_PP,
66*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_REMOVE_BATTERY_BYPASS_PP,
67*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_I2_C,
68*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_FLASH_READ,
69*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_OPEN_NO_DEV_MODE,
70*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_OPEN_FROM_USB,
71*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_OVERRIDE_BATT,
72*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_BOOT_UNVERIFIED_RO,
73*4f2df630SAndroid Build Coastguard Worker TI50_CCD_CAP_COUNT,
74*4f2df630SAndroid Build Coastguard Worker };
75*4f2df630SAndroid Build Coastguard Worker
76*4f2df630SAndroid Build Coastguard Worker static const struct ccd_capability_info ti50_cap_info[] = {
77*4f2df630SAndroid Build Coastguard Worker { "UartGscRxAPTx", CCD_CAP_STATE_ALWAYS },
78*4f2df630SAndroid Build Coastguard Worker { "UartGscTxAPRx", CCD_CAP_STATE_ALWAYS },
79*4f2df630SAndroid Build Coastguard Worker { "UartGscRxECTx", CCD_CAP_STATE_ALWAYS },
80*4f2df630SAndroid Build Coastguard Worker { "UartGscTxECRx", CCD_CAP_STATE_IF_OPENED },
81*4f2df630SAndroid Build Coastguard Worker { "UartGscRxFpmcuTx", CCD_CAP_STATE_ALWAYS },
82*4f2df630SAndroid Build Coastguard Worker { "UartGscTxFpmcuRx", CCD_CAP_STATE_IF_OPENED },
83*4f2df630SAndroid Build Coastguard Worker { "FlashAP", CCD_CAP_STATE_IF_OPENED },
84*4f2df630SAndroid Build Coastguard Worker { "FlashEC", CCD_CAP_STATE_IF_OPENED },
85*4f2df630SAndroid Build Coastguard Worker { "OverrideWP", CCD_CAP_STATE_IF_OPENED },
86*4f2df630SAndroid Build Coastguard Worker { "RebootECAP", CCD_CAP_STATE_IF_OPENED },
87*4f2df630SAndroid Build Coastguard Worker { "GscFullConsole", CCD_CAP_STATE_IF_OPENED },
88*4f2df630SAndroid Build Coastguard Worker { "UnlockNoReboot", CCD_CAP_STATE_ALWAYS },
89*4f2df630SAndroid Build Coastguard Worker { "UnlockNoShortPP", CCD_CAP_STATE_ALWAYS },
90*4f2df630SAndroid Build Coastguard Worker { "OpenNoTPMWipe", CCD_CAP_STATE_IF_OPENED },
91*4f2df630SAndroid Build Coastguard Worker { "OpenNoLongPP", CCD_CAP_STATE_IF_OPENED },
92*4f2df630SAndroid Build Coastguard Worker { "RemoveBatteryBypassPP", CCD_CAP_STATE_ALWAYS },
93*4f2df630SAndroid Build Coastguard Worker { "I2C", CCD_CAP_STATE_IF_OPENED },
94*4f2df630SAndroid Build Coastguard Worker { "FlashRead", CCD_CAP_STATE_ALWAYS },
95*4f2df630SAndroid Build Coastguard Worker /*
96*4f2df630SAndroid Build Coastguard Worker * The below two settings do not match ccd.rs value, which is
97*4f2df630SAndroid Build Coastguard Worker * controlled at compile time.
98*4f2df630SAndroid Build Coastguard Worker */
99*4f2df630SAndroid Build Coastguard Worker { "OpenNoDevMode", CCD_CAP_STATE_IF_OPENED },
100*4f2df630SAndroid Build Coastguard Worker { "OpenFromUSB", CCD_CAP_STATE_IF_OPENED },
101*4f2df630SAndroid Build Coastguard Worker { "OverrideBatt", CCD_CAP_STATE_IF_OPENED },
102*4f2df630SAndroid Build Coastguard Worker /* The below capability is presently set to 'never' in ccd.rs. */
103*4f2df630SAndroid Build Coastguard Worker { "AllowUnverifiedRo", CCD_CAP_STATE_IF_OPENED },
104*4f2df630SAndroid Build Coastguard Worker };
105*4f2df630SAndroid Build Coastguard Worker
106*4f2df630SAndroid Build Coastguard Worker #define CR50_CCD_CAP_COUNT CCD_CAP_COUNT
107*4f2df630SAndroid Build Coastguard Worker
108*4f2df630SAndroid Build Coastguard Worker /*
109*4f2df630SAndroid Build Coastguard Worker * One of the basic assumptions of the code handling multiple ccd_info layouts
110*4f2df630SAndroid Build Coastguard Worker * is that the number of words in the capabilities array is the same for all
111*4f2df630SAndroid Build Coastguard Worker * layouts. Let's verify this at compile time.
112*4f2df630SAndroid Build Coastguard Worker */
113*4f2df630SAndroid Build Coastguard Worker BUILD_ASSERT((CR50_CCD_CAP_COUNT / 32) == (TI50_CCD_CAP_COUNT / 32));
114*4f2df630SAndroid Build Coastguard Worker
115*4f2df630SAndroid Build Coastguard Worker /*
116*4f2df630SAndroid Build Coastguard Worker * Version 0 CCD info packet does not include the header, the actual packet
117*4f2df630SAndroid Build Coastguard Worker * size is used to conclude that the received payload is of version 0.
118*4f2df630SAndroid Build Coastguard Worker *
119*4f2df630SAndroid Build Coastguard Worker * Let's hardcode this size to make sure that it is fixed even if the
120*4f2df630SAndroid Build Coastguard Worker * underlying structure (struct ccd_info_response) size changes in the future.
121*4f2df630SAndroid Build Coastguard Worker */
122*4f2df630SAndroid Build Coastguard Worker #define CCD_INFO_V0_SIZE 23
123*4f2df630SAndroid Build Coastguard Worker
124*4f2df630SAndroid Build Coastguard Worker /*
125*4f2df630SAndroid Build Coastguard Worker * This file contains the source code of a Linux application used to update
126*4f2df630SAndroid Build Coastguard Worker * CR50 device firmware.
127*4f2df630SAndroid Build Coastguard Worker *
128*4f2df630SAndroid Build Coastguard Worker * The CR50 firmware image consists of multiple sections, of interest to this
129*4f2df630SAndroid Build Coastguard Worker * app are the RO and RW code sections, two of each. When firmware update
130*4f2df630SAndroid Build Coastguard Worker * session is established, the CR50 device reports locations of backup RW and RO
131*4f2df630SAndroid Build Coastguard Worker * sections (those not used by the device at the time of transfer).
132*4f2df630SAndroid Build Coastguard Worker *
133*4f2df630SAndroid Build Coastguard Worker * Based on this information this app carves out the appropriate sections form
134*4f2df630SAndroid Build Coastguard Worker * the full CR50 firmware binary image and sends them to the device for
135*4f2df630SAndroid Build Coastguard Worker * programming into flash. Once the new sections are programmed and the device
136*4f2df630SAndroid Build Coastguard Worker * is restarted, the new RO and RW are used if they pass verification and are
137*4f2df630SAndroid Build Coastguard Worker * logically newer than the existing sections.
138*4f2df630SAndroid Build Coastguard Worker *
139*4f2df630SAndroid Build Coastguard Worker * There are two ways to communicate with the CR50 device: USB and /dev/tpm0
140*4f2df630SAndroid Build Coastguard Worker * (when this app is running on a chromebook with the CR50 device). Originally
141*4f2df630SAndroid Build Coastguard Worker * different protocols were used to communicate over different channels,
142*4f2df630SAndroid Build Coastguard Worker * starting with version 3 the same protocol is used.
143*4f2df630SAndroid Build Coastguard Worker *
144*4f2df630SAndroid Build Coastguard Worker * This app provides backwards compatibility to ensure that earlier CR50
145*4f2df630SAndroid Build Coastguard Worker * devices still can be updated.
146*4f2df630SAndroid Build Coastguard Worker *
147*4f2df630SAndroid Build Coastguard Worker *
148*4f2df630SAndroid Build Coastguard Worker * The host (either a local AP or a workstation) is controlling the firmware
149*4f2df630SAndroid Build Coastguard Worker * update protocol, it sends data to the cr50 device, which proceeses it and
150*4f2df630SAndroid Build Coastguard Worker * responds.
151*4f2df630SAndroid Build Coastguard Worker *
152*4f2df630SAndroid Build Coastguard Worker * The encapsultation format is different between the /dev/tpm0 and USB cases:
153*4f2df630SAndroid Build Coastguard Worker *
154*4f2df630SAndroid Build Coastguard Worker * 4 bytes 4 bytes 4 bytes variable size
155*4f2df630SAndroid Build Coastguard Worker * +-----------+--------------+---------------+----------~~--------------+
156*4f2df630SAndroid Build Coastguard Worker * + total size| block digest | dest address | data |
157*4f2df630SAndroid Build Coastguard Worker * +-----------+--------------+---------------+----------~~--------------+
158*4f2df630SAndroid Build Coastguard Worker * \ \ /
159*4f2df630SAndroid Build Coastguard Worker * \ \ /
160*4f2df630SAndroid Build Coastguard Worker * \ +----- FW update PDU sent over /dev/tpm0 -----------+
161*4f2df630SAndroid Build Coastguard Worker * \ /
162*4f2df630SAndroid Build Coastguard Worker * +--------- USB frame, requires total size field ------------+
163*4f2df630SAndroid Build Coastguard Worker *
164*4f2df630SAndroid Build Coastguard Worker * The update protocol data unints (PDUs) are passed over /dev/tpm0, the
165*4f2df630SAndroid Build Coastguard Worker * encapsulation includes integritiy verification and destination address of
166*4f2df630SAndroid Build Coastguard Worker * the data (more of this later). /dev/tpm0 transactions pretty much do not
167*4f2df630SAndroid Build Coastguard Worker * have size limits, whereas the USB data is sent in chunks of the size
168*4f2df630SAndroid Build Coastguard Worker * determined when the USB connestion is set up. This is why USB requires an
169*4f2df630SAndroid Build Coastguard Worker * additional encapsulation into frames to communicate the PDU size to the
170*4f2df630SAndroid Build Coastguard Worker * client side so that the PDU can be reassembled before passing to the
171*4f2df630SAndroid Build Coastguard Worker * programming function.
172*4f2df630SAndroid Build Coastguard Worker *
173*4f2df630SAndroid Build Coastguard Worker * In general, the protocol consists of two phases: connection establishment
174*4f2df630SAndroid Build Coastguard Worker * and actual image transfer.
175*4f2df630SAndroid Build Coastguard Worker *
176*4f2df630SAndroid Build Coastguard Worker * The very first PDU of the transfer session is used to establish the
177*4f2df630SAndroid Build Coastguard Worker * connection. The first PDU does not have any data, and the dest. address
178*4f2df630SAndroid Build Coastguard Worker * field is set to zero. Receiving such a PDU signals the programming function
179*4f2df630SAndroid Build Coastguard Worker * that the host intends to transfer a new image.
180*4f2df630SAndroid Build Coastguard Worker *
181*4f2df630SAndroid Build Coastguard Worker * The response to the first PDU varies depending on the protocol version.
182*4f2df630SAndroid Build Coastguard Worker *
183*4f2df630SAndroid Build Coastguard Worker * Note that protocol versions before 5 are described here for completeness,
184*4f2df630SAndroid Build Coastguard Worker * but are not supported any more by this utility.
185*4f2df630SAndroid Build Coastguard Worker *
186*4f2df630SAndroid Build Coastguard Worker * Version 1 is used over /dev/tpm0. The response is either 4 or 1 bytes in
187*4f2df630SAndroid Build Coastguard Worker * size. The 4 byte response is the *base address* of the backup RW section,
188*4f2df630SAndroid Build Coastguard Worker * no support for RO updates. The one byte response is an error indication,
189*4f2df630SAndroid Build Coastguard Worker * possibly reporting flash erase failure, command format error, etc.
190*4f2df630SAndroid Build Coastguard Worker *
191*4f2df630SAndroid Build Coastguard Worker * Version 2 is used over USB. The response is 8 bytes in size. The first four
192*4f2df630SAndroid Build Coastguard Worker * bytes are either the *base address* of the backup RW section (still no RO
193*4f2df630SAndroid Build Coastguard Worker * updates), or an error code, the same as in Version 1. The second 4 bytes
194*4f2df630SAndroid Build Coastguard Worker * are the protocol version number (set to 2).
195*4f2df630SAndroid Build Coastguard Worker *
196*4f2df630SAndroid Build Coastguard Worker * All versions above 2 behave the same over /dev/tpm0 and USB.
197*4f2df630SAndroid Build Coastguard Worker *
198*4f2df630SAndroid Build Coastguard Worker * Version 3 response is 16 bytes in size. The first 4 bytes are the error code
199*4f2df630SAndroid Build Coastguard Worker * the second 4 bytes are the protocol version (set to 3) and then 4 byte
200*4f2df630SAndroid Build Coastguard Worker * *offset* of the RO section followed by the 4 byte *offset* of the RW section.
201*4f2df630SAndroid Build Coastguard Worker *
202*4f2df630SAndroid Build Coastguard Worker * Version 4 response in addition to version 3 provides header revision fields
203*4f2df630SAndroid Build Coastguard Worker * for active RO and RW images running on the target.
204*4f2df630SAndroid Build Coastguard Worker *
205*4f2df630SAndroid Build Coastguard Worker * Once the connection is established, the image to be programmed into flash
206*4f2df630SAndroid Build Coastguard Worker * is transferred to the CR50 in 1K PDUs. In versions 1 and 2 the address in
207*4f2df630SAndroid Build Coastguard Worker * the header is the absolute address to place the block to, in version 3 and
208*4f2df630SAndroid Build Coastguard Worker * later it is the offset into the flash.
209*4f2df630SAndroid Build Coastguard Worker *
210*4f2df630SAndroid Build Coastguard Worker * Protocol version 5 includes RO and RW key ID information into the first PDU
211*4f2df630SAndroid Build Coastguard Worker * response. The key ID could be used to tell between prod and dev signing
212*4f2df630SAndroid Build Coastguard Worker * modes, among other things.
213*4f2df630SAndroid Build Coastguard Worker *
214*4f2df630SAndroid Build Coastguard Worker * Protocol version 6 does not change the format of the first PDU response,
215*4f2df630SAndroid Build Coastguard Worker * but it indicates the target's ablitiy to channel TPM vendor commands
216*4f2df630SAndroid Build Coastguard Worker * through USB connection.
217*4f2df630SAndroid Build Coastguard Worker *
218*4f2df630SAndroid Build Coastguard Worker * When channeling TPM vendor commands the USB frame looks as follows:
219*4f2df630SAndroid Build Coastguard Worker *
220*4f2df630SAndroid Build Coastguard Worker * 4 bytes 4 bytes 4 bytes 2 bytes variable size
221*4f2df630SAndroid Build Coastguard Worker * +-----------+--------------+---------------+-----------+------~~~-------+
222*4f2df630SAndroid Build Coastguard Worker * + total size| block digest | EXT_CMD | Vend. sub.| data |
223*4f2df630SAndroid Build Coastguard Worker * +-----------+--------------+---------------+-----------+------~~~-------+
224*4f2df630SAndroid Build Coastguard Worker *
225*4f2df630SAndroid Build Coastguard Worker * Where 'Vend. sub' is the vendor subcommand, and data field is subcommand
226*4f2df630SAndroid Build Coastguard Worker * dependent. The target tells between update PDUs and encapsulated vendor
227*4f2df630SAndroid Build Coastguard Worker * subcommands by looking at the EXT_CMD value - it is set to 0xbaccd00a and
228*4f2df630SAndroid Build Coastguard Worker * as such is guaranteed not to be a valid update PDU destination address.
229*4f2df630SAndroid Build Coastguard Worker *
230*4f2df630SAndroid Build Coastguard Worker * The vendor command response size is not fixed, it is subcommand dependent.
231*4f2df630SAndroid Build Coastguard Worker *
232*4f2df630SAndroid Build Coastguard Worker * The CR50 device responds to each update PDU with a confirmation which is 4
233*4f2df630SAndroid Build Coastguard Worker * bytes in size in protocol version 2, and 1 byte in size in all other
234*4f2df630SAndroid Build Coastguard Worker * versions. Zero value means success, non zero value is the error code
235*4f2df630SAndroid Build Coastguard Worker * reported by CR50.
236*4f2df630SAndroid Build Coastguard Worker *
237*4f2df630SAndroid Build Coastguard Worker * Again, vendor command responses are subcommand specific.
238*4f2df630SAndroid Build Coastguard Worker */
239*4f2df630SAndroid Build Coastguard Worker
240*4f2df630SAndroid Build Coastguard Worker /* Look for Cr50 FW update interface */
241*4f2df630SAndroid Build Coastguard Worker #define H1_PID 0x5014
242*4f2df630SAndroid Build Coastguard Worker #define D2_PID 0x504A
243*4f2df630SAndroid Build Coastguard Worker #define NT_PID 0x5066
244*4f2df630SAndroid Build Coastguard Worker #define SUBCLASS USB_SUBCLASS_GOOGLE_CR50
245*4f2df630SAndroid Build Coastguard Worker #define PROTOCOL USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE
246*4f2df630SAndroid Build Coastguard Worker
247*4f2df630SAndroid Build Coastguard Worker /*
248*4f2df630SAndroid Build Coastguard Worker * CCD Info from GSC is communicated using different structure layouts.
249*4f2df630SAndroid Build Coastguard Worker * Version 0 does not have a header and includes just the payload information.
250*4f2df630SAndroid Build Coastguard Worker * Version 2 is prepended by a header which has a distinct value in the first
251*4f2df630SAndroid Build Coastguard Worker * word, and the version number and the total size in the two halfwords after
252*4f2df630SAndroid Build Coastguard Worker * that.
253*4f2df630SAndroid Build Coastguard Worker *
254*4f2df630SAndroid Build Coastguard Worker * Once the payload is received, the absence of the distinct value in the
255*4f2df630SAndroid Build Coastguard Worker * first word and the match of the payload size to the expected size of the
256*4f2df630SAndroid Build Coastguard Worker * version 0 payload indicates that this is indeed a version 0 packet. The
257*4f2df630SAndroid Build Coastguard Worker * distinct first header value and the match of the size field indicates that
258*4f2df630SAndroid Build Coastguard Worker * this is a later version packet.
259*4f2df630SAndroid Build Coastguard Worker */
260*4f2df630SAndroid Build Coastguard Worker #define CCD_INFO_MAGIC 0x49444343 /* This is 'CCDI' in little endian. */
261*4f2df630SAndroid Build Coastguard Worker #define CCD_VERSION 1 /* Ti50 CCD INFO layout. */
262*4f2df630SAndroid Build Coastguard Worker
263*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response_header {
264*4f2df630SAndroid Build Coastguard Worker uint32_t ccd_magic;
265*4f2df630SAndroid Build Coastguard Worker uint16_t ccd_version;
266*4f2df630SAndroid Build Coastguard Worker uint16_t ccd_size;
267*4f2df630SAndroid Build Coastguard Worker } __packed;
268*4f2df630SAndroid Build Coastguard Worker
269*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response_packet {
270*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response_header cir_header;
271*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response cir_body;
272*4f2df630SAndroid Build Coastguard Worker };
273*4f2df630SAndroid Build Coastguard Worker
274*4f2df630SAndroid Build Coastguard Worker /*
275*4f2df630SAndroid Build Coastguard Worker * Need to create an entire TPM PDU when upgrading over /dev/tpm0 and need to
276*4f2df630SAndroid Build Coastguard Worker * have space to prepare the entire PDU.
277*4f2df630SAndroid Build Coastguard Worker */
278*4f2df630SAndroid Build Coastguard Worker struct upgrade_pkt {
279*4f2df630SAndroid Build Coastguard Worker __be16 tag;
280*4f2df630SAndroid Build Coastguard Worker __be32 length;
281*4f2df630SAndroid Build Coastguard Worker __be32 ordinal;
282*4f2df630SAndroid Build Coastguard Worker __be16 subcmd;
283*4f2df630SAndroid Build Coastguard Worker union {
284*4f2df630SAndroid Build Coastguard Worker /*
285*4f2df630SAndroid Build Coastguard Worker * Upgrade PDUs as opposed to all other vendor and extension
286*4f2df630SAndroid Build Coastguard Worker * commands include two additional fields in the header.
287*4f2df630SAndroid Build Coastguard Worker */
288*4f2df630SAndroid Build Coastguard Worker struct {
289*4f2df630SAndroid Build Coastguard Worker __be32 digest;
290*4f2df630SAndroid Build Coastguard Worker __be32 address;
291*4f2df630SAndroid Build Coastguard Worker char data[0];
292*4f2df630SAndroid Build Coastguard Worker } upgrade;
293*4f2df630SAndroid Build Coastguard Worker struct {
294*4f2df630SAndroid Build Coastguard Worker char data[0];
295*4f2df630SAndroid Build Coastguard Worker } command;
296*4f2df630SAndroid Build Coastguard Worker };
297*4f2df630SAndroid Build Coastguard Worker } __packed;
298*4f2df630SAndroid Build Coastguard Worker
299*4f2df630SAndroid Build Coastguard Worker /*
300*4f2df630SAndroid Build Coastguard Worker * Structure used to simplify mapping command line options into Boolean
301*4f2df630SAndroid Build Coastguard Worker * variables. If an option is present, the corresponding integer value is set
302*4f2df630SAndroid Build Coastguard Worker * to 1.
303*4f2df630SAndroid Build Coastguard Worker */
304*4f2df630SAndroid Build Coastguard Worker struct options_map {
305*4f2df630SAndroid Build Coastguard Worker char opt;
306*4f2df630SAndroid Build Coastguard Worker int *flag;
307*4f2df630SAndroid Build Coastguard Worker };
308*4f2df630SAndroid Build Coastguard Worker
309*4f2df630SAndroid Build Coastguard Worker /*
310*4f2df630SAndroid Build Coastguard Worker * Type of the GSC device. This is used to represent which type of GSC we are
311*4f2df630SAndroid Build Coastguard Worker * connected to and to tag an image file for compatibility.
312*4f2df630SAndroid Build Coastguard Worker * for downloading.
313*4f2df630SAndroid Build Coastguard Worker */
314*4f2df630SAndroid Build Coastguard Worker enum gsc_device {
315*4f2df630SAndroid Build Coastguard Worker GSC_DEVICE_H1,
316*4f2df630SAndroid Build Coastguard Worker GSC_DEVICE_DT,
317*4f2df630SAndroid Build Coastguard Worker GSC_DEVICE_NT,
318*4f2df630SAndroid Build Coastguard Worker };
319*4f2df630SAndroid Build Coastguard Worker
320*4f2df630SAndroid Build Coastguard Worker /* Index to refer to a section within sections array */
321*4f2df630SAndroid Build Coastguard Worker enum section {
322*4f2df630SAndroid Build Coastguard Worker RO_A,
323*4f2df630SAndroid Build Coastguard Worker RW_A,
324*4f2df630SAndroid Build Coastguard Worker RO_B,
325*4f2df630SAndroid Build Coastguard Worker RW_B,
326*4f2df630SAndroid Build Coastguard Worker NUM_SECTIONS,
327*4f2df630SAndroid Build Coastguard Worker };
328*4f2df630SAndroid Build Coastguard Worker
329*4f2df630SAndroid Build Coastguard Worker /* Human-readable section names */
330*4f2df630SAndroid Build Coastguard Worker const char *SECTION_NAMES[NUM_SECTIONS] = { [RO_A] = "RO_A",
331*4f2df630SAndroid Build Coastguard Worker [RW_A] = "RW_A",
332*4f2df630SAndroid Build Coastguard Worker [RO_B] = "RO_B",
333*4f2df630SAndroid Build Coastguard Worker [RW_B] = "RW_B" };
334*4f2df630SAndroid Build Coastguard Worker
335*4f2df630SAndroid Build Coastguard Worker /* Describes each of the sections found in the GSC image */
336*4f2df630SAndroid Build Coastguard Worker struct section_t {
337*4f2df630SAndroid Build Coastguard Worker uint32_t offset;
338*4f2df630SAndroid Build Coastguard Worker uint32_t size;
339*4f2df630SAndroid Build Coastguard Worker bool update_needed;
340*4f2df630SAndroid Build Coastguard Worker struct signed_header_version shv;
341*4f2df630SAndroid Build Coastguard Worker uint32_t keyid;
342*4f2df630SAndroid Build Coastguard Worker };
343*4f2df630SAndroid Build Coastguard Worker
344*4f2df630SAndroid Build Coastguard Worker /* Holds a GSC image from disk that can be transfer to a GSC as an update */
345*4f2df630SAndroid Build Coastguard Worker struct image {
346*4f2df630SAndroid Build Coastguard Worker uint8_t *data;
347*4f2df630SAndroid Build Coastguard Worker size_t data_len;
348*4f2df630SAndroid Build Coastguard Worker enum gsc_device type;
349*4f2df630SAndroid Build Coastguard Worker const char *file_path;
350*4f2df630SAndroid Build Coastguard Worker struct section_t sections[NUM_SECTIONS];
351*4f2df630SAndroid Build Coastguard Worker };
352*4f2df630SAndroid Build Coastguard Worker
353*4f2df630SAndroid Build Coastguard Worker /* A header with a GSC device type */
354*4f2df630SAndroid Build Coastguard Worker struct typed_image_header {
355*4f2df630SAndroid Build Coastguard Worker enum gsc_device type;
356*4f2df630SAndroid Build Coastguard Worker union {
357*4f2df630SAndroid Build Coastguard Worker struct SignedHeader *h;
358*4f2df630SAndroid Build Coastguard Worker struct SignedManifest *m;
359*4f2df630SAndroid Build Coastguard Worker };
360*4f2df630SAndroid Build Coastguard Worker };
361*4f2df630SAndroid Build Coastguard Worker
362*4f2df630SAndroid Build Coastguard Worker /*
363*4f2df630SAndroid Build Coastguard Worker * Structure used to combine option description used by getopt_long() and help
364*4f2df630SAndroid Build Coastguard Worker * text for the option.
365*4f2df630SAndroid Build Coastguard Worker */
366*4f2df630SAndroid Build Coastguard Worker struct option_container {
367*4f2df630SAndroid Build Coastguard Worker struct option opt;
368*4f2df630SAndroid Build Coastguard Worker const char *help_text;
369*4f2df630SAndroid Build Coastguard Worker };
370*4f2df630SAndroid Build Coastguard Worker
371*4f2df630SAndroid Build Coastguard Worker static void sha_init(EVP_MD_CTX *ctx);
372*4f2df630SAndroid Build Coastguard Worker static void sha_update(EVP_MD_CTX *ctx, const void *data, size_t len);
373*4f2df630SAndroid Build Coastguard Worker static void sha_final_into_block_digest(EVP_MD_CTX *ctx, void *block_digest,
374*4f2df630SAndroid Build Coastguard Worker size_t size);
375*4f2df630SAndroid Build Coastguard Worker
376*4f2df630SAndroid Build Coastguard Worker /* Type of the GSC device we are talking to, determined at run time. */
377*4f2df630SAndroid Build Coastguard Worker static enum gsc_device gsc_dev = GSC_DEVICE_H1;
378*4f2df630SAndroid Build Coastguard Worker
379*4f2df630SAndroid Build Coastguard Worker /*
380*4f2df630SAndroid Build Coastguard Worker * Current AP RO verification config setting version
381*4f2df630SAndroid Build Coastguard Worker */
382*4f2df630SAndroid Build Coastguard Worker #define ARV_CONFIG_SETTING_CURRENT_VERSION 0x01
383*4f2df630SAndroid Build Coastguard Worker
384*4f2df630SAndroid Build Coastguard Worker /*
385*4f2df630SAndroid Build Coastguard Worker * AP RO verification config setting command choices
386*4f2df630SAndroid Build Coastguard Worker */
387*4f2df630SAndroid Build Coastguard Worker enum arv_config_setting_command_e {
388*4f2df630SAndroid Build Coastguard Worker arv_config_setting_command_spi_addressing_mode = 0,
389*4f2df630SAndroid Build Coastguard Worker arv_config_setting_command_write_protect_descriptors = 1,
390*4f2df630SAndroid Build Coastguard Worker };
391*4f2df630SAndroid Build Coastguard Worker
392*4f2df630SAndroid Build Coastguard Worker /*
393*4f2df630SAndroid Build Coastguard Worker * AP RO verification config setting state
394*4f2df630SAndroid Build Coastguard Worker */
395*4f2df630SAndroid Build Coastguard Worker enum arv_config_setting_state_e {
396*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_present = 0,
397*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_not_present = 1,
398*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_corrupted = 2,
399*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_invalid = 3,
400*4f2df630SAndroid Build Coastguard Worker };
401*4f2df630SAndroid Build Coastguard Worker
402*4f2df630SAndroid Build Coastguard Worker /*
403*4f2df630SAndroid Build Coastguard Worker * AP RO verification SPI read/write addressing mode configuration choices
404*4f2df630SAndroid Build Coastguard Worker */
405*4f2df630SAndroid Build Coastguard Worker enum arv_config_spi_addr_mode_e {
406*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_none = 0,
407*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_get = 1,
408*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_set_3byte = 2,
409*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_set_4byte = 3,
410*4f2df630SAndroid Build Coastguard Worker };
411*4f2df630SAndroid Build Coastguard Worker
412*4f2df630SAndroid Build Coastguard Worker /*
413*4f2df630SAndroid Build Coastguard Worker * AP RO verification write protect descriptor configuration choices
414*4f2df630SAndroid Build Coastguard Worker */
415*4f2df630SAndroid Build Coastguard Worker enum arv_config_wpsr_choice_e {
416*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice_none = 0,
417*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice_get = 1,
418*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice_set = 2,
419*4f2df630SAndroid Build Coastguard Worker };
420*4f2df630SAndroid Build Coastguard Worker
421*4f2df630SAndroid Build Coastguard Worker /*
422*4f2df630SAndroid Build Coastguard Worker * AP RO verification write protect descriptor information
423*4f2df630SAndroid Build Coastguard Worker */
424*4f2df630SAndroid Build Coastguard Worker struct __attribute__((__packed__)) arv_config_wpd {
425*4f2df630SAndroid Build Coastguard Worker /* See `arv_config_setting_state_e` */
426*4f2df630SAndroid Build Coastguard Worker uint8_t state;
427*4f2df630SAndroid Build Coastguard Worker uint8_t expected_value;
428*4f2df630SAndroid Build Coastguard Worker uint8_t mask;
429*4f2df630SAndroid Build Coastguard Worker };
430*4f2df630SAndroid Build Coastguard Worker
431*4f2df630SAndroid Build Coastguard Worker /*
432*4f2df630SAndroid Build Coastguard Worker * AP RO verification write protect descriptors. This is a helper type to
433*4f2df630SAndroid Build Coastguard Worker * represent the three write protect descriptors.
434*4f2df630SAndroid Build Coastguard Worker */
435*4f2df630SAndroid Build Coastguard Worker struct __attribute__((__packed__)) arv_config_wpds {
436*4f2df630SAndroid Build Coastguard Worker struct arv_config_wpd data[3];
437*4f2df630SAndroid Build Coastguard Worker };
438*4f2df630SAndroid Build Coastguard Worker
439*4f2df630SAndroid Build Coastguard Worker /*
440*4f2df630SAndroid Build Coastguard Worker * This matches the largest vendor command response size we ever expect.
441*4f2df630SAndroid Build Coastguard Worker */
442*4f2df630SAndroid Build Coastguard Worker #define MAX_RX_BUF_SIZE 2048
443*4f2df630SAndroid Build Coastguard Worker
444*4f2df630SAndroid Build Coastguard Worker /*
445*4f2df630SAndroid Build Coastguard Worker * Maximum update payload block size plus packet header size.
446*4f2df630SAndroid Build Coastguard Worker */
447*4f2df630SAndroid Build Coastguard Worker #define MAX_TX_BUF_SIZE (SIGNED_TRANSFER_SIZE + sizeof(struct upgrade_pkt))
448*4f2df630SAndroid Build Coastguard Worker
449*4f2df630SAndroid Build Coastguard Worker /*
450*4f2df630SAndroid Build Coastguard Worker * Max. length of the board ID string representation.
451*4f2df630SAndroid Build Coastguard Worker *
452*4f2df630SAndroid Build Coastguard Worker * Board ID is either a 4-character ASCII alphanumeric string or an 8-digit
453*4f2df630SAndroid Build Coastguard Worker * hex.
454*4f2df630SAndroid Build Coastguard Worker */
455*4f2df630SAndroid Build Coastguard Worker #define MAX_BOARD_ID_LENGTH 9
456*4f2df630SAndroid Build Coastguard Worker
457*4f2df630SAndroid Build Coastguard Worker /*
458*4f2df630SAndroid Build Coastguard Worker * Length, in bytes, of the SN Bits serial number bits.
459*4f2df630SAndroid Build Coastguard Worker */
460*4f2df630SAndroid Build Coastguard Worker #define SN_BITS_SIZE (96 >> 3)
461*4f2df630SAndroid Build Coastguard Worker
462*4f2df630SAndroid Build Coastguard Worker /*
463*4f2df630SAndroid Build Coastguard Worker * Max. length of FW version in the format of <epoch>.<major>.<minor>
464*4f2df630SAndroid Build Coastguard Worker * (3 uint32_t string representation + 2 separators + NULL terminator).
465*4f2df630SAndroid Build Coastguard Worker */
466*4f2df630SAndroid Build Coastguard Worker #define MAX_FW_VER_LENGTH 33
467*4f2df630SAndroid Build Coastguard Worker
468*4f2df630SAndroid Build Coastguard Worker static int verbose_mode;
469*4f2df630SAndroid Build Coastguard Worker static uint32_t protocol_version;
470*4f2df630SAndroid Build Coastguard Worker static char *progname;
471*4f2df630SAndroid Build Coastguard Worker
472*4f2df630SAndroid Build Coastguard Worker /*
473*4f2df630SAndroid Build Coastguard Worker * List of command line options, ***sorted by the short form***.
474*4f2df630SAndroid Build Coastguard Worker *
475*4f2df630SAndroid Build Coastguard Worker * The help_text field does not include the short and long option strings,
476*4f2df630SAndroid Build Coastguard Worker * they are retrieved from the opt structure. In case the help text needs to
477*4f2df630SAndroid Build Coastguard Worker * have something printed immediately after the option strings (for example,
478*4f2df630SAndroid Build Coastguard Worker * an optional parameter), it should be included in the beginning of help_text
479*4f2df630SAndroid Build Coastguard Worker * string separated by the % character.
480*4f2df630SAndroid Build Coastguard Worker *
481*4f2df630SAndroid Build Coastguard Worker * usage() function which prints out the help message will concatenate the
482*4f2df630SAndroid Build Coastguard Worker * short and long options and the optional parameter, if present, and then
483*4f2df630SAndroid Build Coastguard Worker * print the rest of the text message at a fixed indentation.
484*4f2df630SAndroid Build Coastguard Worker */
485*4f2df630SAndroid Build Coastguard Worker static const struct option_container cmd_line_options[] = {
486*4f2df630SAndroid Build Coastguard Worker /* {{name has_arg *flag val} long_desc dev_type} */
487*4f2df630SAndroid Build Coastguard Worker { { "get_apro_hash", no_argument, NULL, 'A' },
488*4f2df630SAndroid Build Coastguard Worker "get the stored ap ro hash" },
489*4f2df630SAndroid Build Coastguard Worker { { "any", no_argument, NULL, 'a' },
490*4f2df630SAndroid Build Coastguard Worker "Try any interfaces to find Cr50"
491*4f2df630SAndroid Build Coastguard Worker " (-d, -s, -t are all ignored)" },
492*4f2df630SAndroid Build Coastguard Worker { { "apro_boot", optional_argument, NULL, 'B' },
493*4f2df630SAndroid Build Coastguard Worker "[start] get the stored ap ro boot state or start ap ro verify" },
494*4f2df630SAndroid Build Coastguard Worker { { "binvers", no_argument, NULL, 'b' },
495*4f2df630SAndroid Build Coastguard Worker "Report versions of Cr50 image's "
496*4f2df630SAndroid Build Coastguard Worker "RW and RO headers, do not update" },
497*4f2df630SAndroid Build Coastguard Worker { { "apro_config_spi_mode", optional_argument, NULL, 'C' },
498*4f2df630SAndroid Build Coastguard Worker "Get/set the ap ro verify spi mode either to `3byte` or `4byte`" },
499*4f2df630SAndroid Build Coastguard Worker { { "corrupt", no_argument, NULL, 'c' }, "Corrupt the inactive rw" },
500*4f2df630SAndroid Build Coastguard Worker { { "dauntless", no_argument, NULL, 'D' },
501*4f2df630SAndroid Build Coastguard Worker "Deprecated. No longer needed as runtime selection is used." },
502*4f2df630SAndroid Build Coastguard Worker { { "device", required_argument, NULL, 'd' },
503*4f2df630SAndroid Build Coastguard Worker "VID:PID%USB device (default 18d1:5014 or 18d1:504a based on"
504*4f2df630SAndroid Build Coastguard Worker " image)" },
505*4f2df630SAndroid Build Coastguard Worker { { "apro_config_write_protect", optional_argument, NULL, 'E' },
506*4f2df630SAndroid Build Coastguard Worker "Get/set the ap ro verify write protect descriptors with hex "
507*4f2df630SAndroid Build Coastguard Worker "bytes (ex: 0x01, 0x1, 01 or 1) in the following format: "
508*4f2df630SAndroid Build Coastguard Worker "[sr1 mask1 [sr2 mask2] [sr3 mask3]]" },
509*4f2df630SAndroid Build Coastguard Worker { { "endorsement_seed", optional_argument, NULL, 'e' },
510*4f2df630SAndroid Build Coastguard Worker "[state]%get/set the endorsement key seed" },
511*4f2df630SAndroid Build Coastguard Worker { { "factory", required_argument, NULL, 'F' },
512*4f2df630SAndroid Build Coastguard Worker "[enable|disable]%Control factory mode" },
513*4f2df630SAndroid Build Coastguard Worker { { "fwver", no_argument, NULL, 'f' },
514*4f2df630SAndroid Build Coastguard Worker "Report running Cr50 firmware versions" },
515*4f2df630SAndroid Build Coastguard Worker { { "get_time", no_argument, NULL, 'G' },
516*4f2df630SAndroid Build Coastguard Worker "Get time since last cold reset" },
517*4f2df630SAndroid Build Coastguard Worker { { "getbootmode", no_argument, NULL, 'g' },
518*4f2df630SAndroid Build Coastguard Worker "Get the system boot mode" },
519*4f2df630SAndroid Build Coastguard Worker { { "erase_ap_ro_hash", no_argument, NULL, 'H' },
520*4f2df630SAndroid Build Coastguard Worker "Erase AP RO hash (possible only if Board ID is not set)" },
521*4f2df630SAndroid Build Coastguard Worker { { "help", no_argument, NULL, 'h' }, "Show this message" },
522*4f2df630SAndroid Build Coastguard Worker { { "ccd_info", optional_argument, NULL, 'I' },
523*4f2df630SAndroid Build Coastguard Worker "[capability:value]%Get information about CCD state or set capability"
524*4f2df630SAndroid Build Coastguard Worker " value if allowed" },
525*4f2df630SAndroid Build Coastguard Worker { { "board_id", optional_argument, NULL, 'i' },
526*4f2df630SAndroid Build Coastguard Worker "[ID[:FLAGS]]%Get or set Info1 board ID fields. ID could be 32 bit "
527*4f2df630SAndroid Build Coastguard Worker "hex or 4 character string." },
528*4f2df630SAndroid Build Coastguard Worker { { "boot_trace", optional_argument, NULL, 'J' },
529*4f2df630SAndroid Build Coastguard Worker "[erase]%Retrieve boot trace from the chip, optionally erasing "
530*4f2df630SAndroid Build Coastguard Worker "the trace buffer" },
531*4f2df630SAndroid Build Coastguard Worker { { "get_value", required_argument, NULL, 'K' },
532*4f2df630SAndroid Build Coastguard Worker "[chassis_open|dev_ids]%Get properties values" },
533*4f2df630SAndroid Build Coastguard Worker { { "ccd_lock", no_argument, NULL, 'k' }, "Lock CCD" },
534*4f2df630SAndroid Build Coastguard Worker { { "flog", optional_argument, NULL, 'L' },
535*4f2df630SAndroid Build Coastguard Worker "[prev entry]%Retrieve contents of the flash log"
536*4f2df630SAndroid Build Coastguard Worker " (newer than <prev entry> if specified)" },
537*4f2df630SAndroid Build Coastguard Worker { { "console", no_argument, NULL, 'l' },
538*4f2df630SAndroid Build Coastguard Worker "Get console logs. This may need to be run multiple times to collect "
539*4f2df630SAndroid Build Coastguard Worker "all available logs." },
540*4f2df630SAndroid Build Coastguard Worker { { "machine", no_argument, NULL, 'M' },
541*4f2df630SAndroid Build Coastguard Worker "Output in a machine-friendly way. "
542*4f2df630SAndroid Build Coastguard Worker "Effective with -b, -f, -i, -J, -r, and -O." },
543*4f2df630SAndroid Build Coastguard Worker { { "tpm_mode", optional_argument, NULL, 'm' },
544*4f2df630SAndroid Build Coastguard Worker "[enable|disable]%Change or query tpm_mode" },
545*4f2df630SAndroid Build Coastguard Worker { { "serial", required_argument, NULL, 'n' }, "GSC USB serial number" },
546*4f2df630SAndroid Build Coastguard Worker { { "openbox_rma", required_argument, NULL, 'O' },
547*4f2df630SAndroid Build Coastguard Worker "<desc_file>%Verify other device's RO integrity using information "
548*4f2df630SAndroid Build Coastguard Worker "provided in <desc file>" },
549*4f2df630SAndroid Build Coastguard Worker { { "ccd_open", no_argument, NULL, 'o' }, "Start CCD open sequence" },
550*4f2df630SAndroid Build Coastguard Worker { { "password", no_argument, NULL, 'P' },
551*4f2df630SAndroid Build Coastguard Worker "Set or clear CCD password. Use 'clear:<cur password>' to clear it" },
552*4f2df630SAndroid Build Coastguard Worker { { "post_reset", no_argument, NULL, 'p' },
553*4f2df630SAndroid Build Coastguard Worker "Request post reset after transfer" },
554*4f2df630SAndroid Build Coastguard Worker { { "force_ro", no_argument, NULL, 'q' }, "Force inactive RO update" },
555*4f2df630SAndroid Build Coastguard Worker { { "sn_rma_inc", required_argument, NULL, 'R' },
556*4f2df630SAndroid Build Coastguard Worker "RMA_INC%Increment SN RMA count by RMA_INC. RMA_INC should be 0-7." },
557*4f2df630SAndroid Build Coastguard Worker { { "rma_auth", optional_argument, NULL, 'r' },
558*4f2df630SAndroid Build Coastguard Worker "[auth_code]%Request RMA challenge, process "
559*4f2df630SAndroid Build Coastguard Worker "RMA authentication code" },
560*4f2df630SAndroid Build Coastguard Worker { { "sn_bits", required_argument, NULL, 'S' },
561*4f2df630SAndroid Build Coastguard Worker "SN_BITS%Set Info1 SN bits fields. SN_BITS should be 96 bit hex." },
562*4f2df630SAndroid Build Coastguard Worker { { "systemdev", no_argument, NULL, 's' },
563*4f2df630SAndroid Build Coastguard Worker "Use /dev/tpm0 (-d is ignored)" },
564*4f2df630SAndroid Build Coastguard Worker { { "tstamp", optional_argument, NULL, 'T' },
565*4f2df630SAndroid Build Coastguard Worker "[<tstamp>]%Get or set flash log timestamp base" },
566*4f2df630SAndroid Build Coastguard Worker { { "trunks_send", no_argument, NULL, 't' },
567*4f2df630SAndroid Build Coastguard Worker "Use `trunks_send --raw' (-d is ignored)" },
568*4f2df630SAndroid Build Coastguard Worker { { "ccd_unlock", no_argument, NULL, 'U' },
569*4f2df630SAndroid Build Coastguard Worker "Start CCD unlock sequence" },
570*4f2df630SAndroid Build Coastguard Worker { { "upstart", no_argument, NULL, 'u' },
571*4f2df630SAndroid Build Coastguard Worker "Upstart mode (strict header checks)" },
572*4f2df630SAndroid Build Coastguard Worker { { "verbose", no_argument, NULL, 'V' }, "Enable debug messages" },
573*4f2df630SAndroid Build Coastguard Worker { { "version", no_argument, NULL, 'v' },
574*4f2df630SAndroid Build Coastguard Worker "Report this utility version" },
575*4f2df630SAndroid Build Coastguard Worker { { "metrics", no_argument, NULL, 'W' }, "Get GSC metrics" },
576*4f2df630SAndroid Build Coastguard Worker { { "wp", optional_argument, NULL, 'w' },
577*4f2df630SAndroid Build Coastguard Worker "[enable|disable|follow]%Get or set the write protect setting" },
578*4f2df630SAndroid Build Coastguard Worker { { "clog", no_argument, NULL, 'x' },
579*4f2df630SAndroid Build Coastguard Worker "Retrieve contents of the most recent crash log." },
580*4f2df630SAndroid Build Coastguard Worker { { "factory_config", optional_argument, NULL, 'y' },
581*4f2df630SAndroid Build Coastguard Worker "[value]%Sets the factory config bits in INFO. value should be 64 "
582*4f2df630SAndroid Build Coastguard Worker "bit hex." },
583*4f2df630SAndroid Build Coastguard Worker { { "reboot", optional_argument, NULL, 'z' },
584*4f2df630SAndroid Build Coastguard Worker "Tell the GSC to reboot with an optional reset timeout parameter "
585*4f2df630SAndroid Build Coastguard Worker "in milliseconds" },
586*4f2df630SAndroid Build Coastguard Worker };
587*4f2df630SAndroid Build Coastguard Worker
588*4f2df630SAndroid Build Coastguard Worker /* Helper to print debug messages when verbose flag is specified. */
debug(const char * fmt,...)589*4f2df630SAndroid Build Coastguard Worker static void debug(const char *fmt, ...)
590*4f2df630SAndroid Build Coastguard Worker {
591*4f2df630SAndroid Build Coastguard Worker va_list args;
592*4f2df630SAndroid Build Coastguard Worker
593*4f2df630SAndroid Build Coastguard Worker if (verbose_mode) {
594*4f2df630SAndroid Build Coastguard Worker va_start(args, fmt);
595*4f2df630SAndroid Build Coastguard Worker vprintf(fmt, args);
596*4f2df630SAndroid Build Coastguard Worker va_end(args);
597*4f2df630SAndroid Build Coastguard Worker }
598*4f2df630SAndroid Build Coastguard Worker }
599*4f2df630SAndroid Build Coastguard Worker
600*4f2df630SAndroid Build Coastguard Worker /* Helpers to convert between binary and hex ascii and back. */
to_hexascii(uint8_t c)601*4f2df630SAndroid Build Coastguard Worker static char to_hexascii(uint8_t c)
602*4f2df630SAndroid Build Coastguard Worker {
603*4f2df630SAndroid Build Coastguard Worker if (c <= 9)
604*4f2df630SAndroid Build Coastguard Worker return '0' + c;
605*4f2df630SAndroid Build Coastguard Worker return 'a' + c - 10;
606*4f2df630SAndroid Build Coastguard Worker }
607*4f2df630SAndroid Build Coastguard Worker
from_hexascii(char c)608*4f2df630SAndroid Build Coastguard Worker static int from_hexascii(char c)
609*4f2df630SAndroid Build Coastguard Worker {
610*4f2df630SAndroid Build Coastguard Worker /* convert to lower case. */
611*4f2df630SAndroid Build Coastguard Worker c = tolower(c);
612*4f2df630SAndroid Build Coastguard Worker
613*4f2df630SAndroid Build Coastguard Worker if (c < '0' || c > 'f' || ((c > '9') && (c < 'a')))
614*4f2df630SAndroid Build Coastguard Worker return -1; /* Not an ascii character. */
615*4f2df630SAndroid Build Coastguard Worker
616*4f2df630SAndroid Build Coastguard Worker if (c <= '9')
617*4f2df630SAndroid Build Coastguard Worker return c - '0';
618*4f2df630SAndroid Build Coastguard Worker
619*4f2df630SAndroid Build Coastguard Worker return c - 'a' + 10;
620*4f2df630SAndroid Build Coastguard Worker }
621*4f2df630SAndroid Build Coastguard Worker
622*4f2df630SAndroid Build Coastguard Worker /* Returns true if the connected GSC device has Ti50-based firmware. */
is_ti50_device(void)623*4f2df630SAndroid Build Coastguard Worker static bool is_ti50_device(void)
624*4f2df630SAndroid Build Coastguard Worker {
625*4f2df630SAndroid Build Coastguard Worker /* Assume Ti50 is not H1 device. */
626*4f2df630SAndroid Build Coastguard Worker return gsc_dev != GSC_DEVICE_H1;
627*4f2df630SAndroid Build Coastguard Worker }
628*4f2df630SAndroid Build Coastguard Worker
629*4f2df630SAndroid Build Coastguard Worker /* Functions to communicate with the TPM over the trunks_send --raw channel. */
630*4f2df630SAndroid Build Coastguard Worker
631*4f2df630SAndroid Build Coastguard Worker /* File handle to share between write and read sides. */
632*4f2df630SAndroid Build Coastguard Worker static FILE *tpm_output;
ts_write(const void * out,size_t len)633*4f2df630SAndroid Build Coastguard Worker static int ts_write(const void *out, size_t len)
634*4f2df630SAndroid Build Coastguard Worker {
635*4f2df630SAndroid Build Coastguard Worker const char *cmd_head = "PATH=\"${PATH}:/usr/sbin:/vendor/bin/hw\" "
636*4f2df630SAndroid Build Coastguard Worker "${TRUNKS_SEND_BIN:-trunks_send} --raw ";
637*4f2df630SAndroid Build Coastguard Worker size_t head_size = strlen(cmd_head);
638*4f2df630SAndroid Build Coastguard Worker char full_command[head_size + 2 * len + 1];
639*4f2df630SAndroid Build Coastguard Worker size_t i;
640*4f2df630SAndroid Build Coastguard Worker
641*4f2df630SAndroid Build Coastguard Worker strcpy(full_command, cmd_head);
642*4f2df630SAndroid Build Coastguard Worker /*
643*4f2df630SAndroid Build Coastguard Worker * Need to convert binary input into hex ascii output to pass to the
644*4f2df630SAndroid Build Coastguard Worker * trunks_send command.
645*4f2df630SAndroid Build Coastguard Worker */
646*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
647*4f2df630SAndroid Build Coastguard Worker uint8_t c = ((const uint8_t *)out)[i];
648*4f2df630SAndroid Build Coastguard Worker
649*4f2df630SAndroid Build Coastguard Worker full_command[head_size + 2 * i] = to_hexascii(c >> 4);
650*4f2df630SAndroid Build Coastguard Worker full_command[head_size + 2 * i + 1] = to_hexascii(c & 0xf);
651*4f2df630SAndroid Build Coastguard Worker }
652*4f2df630SAndroid Build Coastguard Worker
653*4f2df630SAndroid Build Coastguard Worker /* Make it a proper zero terminated string. */
654*4f2df630SAndroid Build Coastguard Worker full_command[sizeof(full_command) - 1] = 0;
655*4f2df630SAndroid Build Coastguard Worker debug("cmd: %s\n", full_command);
656*4f2df630SAndroid Build Coastguard Worker tpm_output = popen(full_command, "r");
657*4f2df630SAndroid Build Coastguard Worker if (tpm_output)
658*4f2df630SAndroid Build Coastguard Worker return len;
659*4f2df630SAndroid Build Coastguard Worker
660*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: failed to launch trunks_send --raw\n");
661*4f2df630SAndroid Build Coastguard Worker return -1;
662*4f2df630SAndroid Build Coastguard Worker }
663*4f2df630SAndroid Build Coastguard Worker
ts_read(void * buf,size_t max_rx_size)664*4f2df630SAndroid Build Coastguard Worker static int ts_read(void *buf, size_t max_rx_size)
665*4f2df630SAndroid Build Coastguard Worker {
666*4f2df630SAndroid Build Coastguard Worker int i;
667*4f2df630SAndroid Build Coastguard Worker int pclose_rv;
668*4f2df630SAndroid Build Coastguard Worker int rv;
669*4f2df630SAndroid Build Coastguard Worker /* +1 to account for '\n' added by trunks_send. */
670*4f2df630SAndroid Build Coastguard Worker char response[max_rx_size * 2 + 1];
671*4f2df630SAndroid Build Coastguard Worker
672*4f2df630SAndroid Build Coastguard Worker if (!tpm_output) {
673*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: attempt to read empty output\n");
674*4f2df630SAndroid Build Coastguard Worker return -1;
675*4f2df630SAndroid Build Coastguard Worker }
676*4f2df630SAndroid Build Coastguard Worker
677*4f2df630SAndroid Build Coastguard Worker rv = fread(response, 1, sizeof(response), tpm_output);
678*4f2df630SAndroid Build Coastguard Worker if (rv > 0)
679*4f2df630SAndroid Build Coastguard Worker rv -= 1; /* Discard the \n character added by trunks_send. */
680*4f2df630SAndroid Build Coastguard Worker
681*4f2df630SAndroid Build Coastguard Worker debug("response of size %d, max rx size %zd: %s\n", rv, max_rx_size,
682*4f2df630SAndroid Build Coastguard Worker response);
683*4f2df630SAndroid Build Coastguard Worker
684*4f2df630SAndroid Build Coastguard Worker pclose_rv = pclose(tpm_output);
685*4f2df630SAndroid Build Coastguard Worker if (pclose_rv < 0) {
686*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: pclose failed: error %d (%s)\n", errno,
687*4f2df630SAndroid Build Coastguard Worker strerror(errno));
688*4f2df630SAndroid Build Coastguard Worker return -1;
689*4f2df630SAndroid Build Coastguard Worker }
690*4f2df630SAndroid Build Coastguard Worker
691*4f2df630SAndroid Build Coastguard Worker tpm_output = NULL;
692*4f2df630SAndroid Build Coastguard Worker
693*4f2df630SAndroid Build Coastguard Worker if (rv & 1) {
694*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
695*4f2df630SAndroid Build Coastguard Worker "Error: trunks_send returned odd number of bytes: %s\n",
696*4f2df630SAndroid Build Coastguard Worker response);
697*4f2df630SAndroid Build Coastguard Worker return -1;
698*4f2df630SAndroid Build Coastguard Worker }
699*4f2df630SAndroid Build Coastguard Worker
700*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < rv / 2; i++) {
701*4f2df630SAndroid Build Coastguard Worker uint8_t byte;
702*4f2df630SAndroid Build Coastguard Worker char c;
703*4f2df630SAndroid Build Coastguard Worker int nibble;
704*4f2df630SAndroid Build Coastguard Worker
705*4f2df630SAndroid Build Coastguard Worker c = response[2 * i];
706*4f2df630SAndroid Build Coastguard Worker nibble = from_hexascii(c);
707*4f2df630SAndroid Build Coastguard Worker if (nibble < 0) {
708*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
709*4f2df630SAndroid Build Coastguard Worker "Error: "
710*4f2df630SAndroid Build Coastguard Worker "trunks_send returned non hex character %c\n",
711*4f2df630SAndroid Build Coastguard Worker c);
712*4f2df630SAndroid Build Coastguard Worker return -1;
713*4f2df630SAndroid Build Coastguard Worker }
714*4f2df630SAndroid Build Coastguard Worker byte = nibble << 4;
715*4f2df630SAndroid Build Coastguard Worker
716*4f2df630SAndroid Build Coastguard Worker c = response[2 * i + 1];
717*4f2df630SAndroid Build Coastguard Worker nibble = from_hexascii(c);
718*4f2df630SAndroid Build Coastguard Worker if (nibble < 0) {
719*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
720*4f2df630SAndroid Build Coastguard Worker "Error: "
721*4f2df630SAndroid Build Coastguard Worker "trunks_send returned non hex character %c\n",
722*4f2df630SAndroid Build Coastguard Worker c);
723*4f2df630SAndroid Build Coastguard Worker return -1;
724*4f2df630SAndroid Build Coastguard Worker }
725*4f2df630SAndroid Build Coastguard Worker byte |= nibble;
726*4f2df630SAndroid Build Coastguard Worker
727*4f2df630SAndroid Build Coastguard Worker ((uint8_t *)buf)[i] = byte;
728*4f2df630SAndroid Build Coastguard Worker }
729*4f2df630SAndroid Build Coastguard Worker
730*4f2df630SAndroid Build Coastguard Worker return rv / 2;
731*4f2df630SAndroid Build Coastguard Worker }
732*4f2df630SAndroid Build Coastguard Worker
733*4f2df630SAndroid Build Coastguard Worker /*
734*4f2df630SAndroid Build Coastguard Worker * Prepare and transfer a block to either to /dev/tpm0 or through trunks_send
735*4f2df630SAndroid Build Coastguard Worker * --raw, get a reply.
736*4f2df630SAndroid Build Coastguard Worker */
tpm_send_pkt(struct transfer_descriptor * td,unsigned int digest,unsigned int addr,const void * data,int size,void * response,size_t * response_size,uint16_t subcmd)737*4f2df630SAndroid Build Coastguard Worker static int tpm_send_pkt(struct transfer_descriptor *td, unsigned int digest,
738*4f2df630SAndroid Build Coastguard Worker unsigned int addr, const void *data, int size,
739*4f2df630SAndroid Build Coastguard Worker void *response, size_t *response_size, uint16_t subcmd)
740*4f2df630SAndroid Build Coastguard Worker {
741*4f2df630SAndroid Build Coastguard Worker /* Used by transfer to /dev/tpm0 */
742*4f2df630SAndroid Build Coastguard Worker static uint8_t outbuf[MAX_TX_BUF_SIZE];
743*4f2df630SAndroid Build Coastguard Worker static uint8_t
744*4f2df630SAndroid Build Coastguard Worker raw_response[MAX_RX_BUF_SIZE + sizeof(struct upgrade_pkt)];
745*4f2df630SAndroid Build Coastguard Worker struct upgrade_pkt *out = (struct upgrade_pkt *)outbuf;
746*4f2df630SAndroid Build Coastguard Worker int len, done;
747*4f2df630SAndroid Build Coastguard Worker int response_offset = offsetof(struct upgrade_pkt, command.data);
748*4f2df630SAndroid Build Coastguard Worker void *payload;
749*4f2df630SAndroid Build Coastguard Worker size_t header_size;
750*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
751*4f2df630SAndroid Build Coastguard Worker const size_t rx_size = sizeof(raw_response);
752*4f2df630SAndroid Build Coastguard Worker
753*4f2df630SAndroid Build Coastguard Worker debug("%s: sending to %#x %d bytes\n", __func__, addr, size);
754*4f2df630SAndroid Build Coastguard Worker
755*4f2df630SAndroid Build Coastguard Worker out->tag = htobe16(0x8001);
756*4f2df630SAndroid Build Coastguard Worker out->subcmd = htobe16(subcmd);
757*4f2df630SAndroid Build Coastguard Worker
758*4f2df630SAndroid Build Coastguard Worker if (subcmd <= LAST_EXTENSION_COMMAND)
759*4f2df630SAndroid Build Coastguard Worker out->ordinal = htobe32(CONFIG_EXTENSION_COMMAND);
760*4f2df630SAndroid Build Coastguard Worker else
761*4f2df630SAndroid Build Coastguard Worker out->ordinal = htobe32(TPM_CC_VENDOR_BIT_MASK);
762*4f2df630SAndroid Build Coastguard Worker
763*4f2df630SAndroid Build Coastguard Worker if (subcmd == EXTENSION_FW_UPGRADE) {
764*4f2df630SAndroid Build Coastguard Worker /* FW Upgrade PDU header includes a couple of extra fields. */
765*4f2df630SAndroid Build Coastguard Worker out->upgrade.digest = digest;
766*4f2df630SAndroid Build Coastguard Worker out->upgrade.address = htobe32(addr);
767*4f2df630SAndroid Build Coastguard Worker header_size = offsetof(struct upgrade_pkt, upgrade.data);
768*4f2df630SAndroid Build Coastguard Worker } else {
769*4f2df630SAndroid Build Coastguard Worker header_size = offsetof(struct upgrade_pkt, command.data);
770*4f2df630SAndroid Build Coastguard Worker }
771*4f2df630SAndroid Build Coastguard Worker
772*4f2df630SAndroid Build Coastguard Worker payload = outbuf + header_size;
773*4f2df630SAndroid Build Coastguard Worker len = size + header_size;
774*4f2df630SAndroid Build Coastguard Worker
775*4f2df630SAndroid Build Coastguard Worker out->length = htobe32(len);
776*4f2df630SAndroid Build Coastguard Worker memcpy(payload, data, size);
777*4f2df630SAndroid Build Coastguard Worker
778*4f2df630SAndroid Build Coastguard Worker if (verbose_mode) {
779*4f2df630SAndroid Build Coastguard Worker int i;
780*4f2df630SAndroid Build Coastguard Worker
781*4f2df630SAndroid Build Coastguard Worker debug("Writing %d bytes to TPM at %x\n", len, addr);
782*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < MIN(len, 20); i++)
783*4f2df630SAndroid Build Coastguard Worker debug("%2.2x ", outbuf[i]);
784*4f2df630SAndroid Build Coastguard Worker debug("\n");
785*4f2df630SAndroid Build Coastguard Worker }
786*4f2df630SAndroid Build Coastguard Worker
787*4f2df630SAndroid Build Coastguard Worker switch (td->ep_type) {
788*4f2df630SAndroid Build Coastguard Worker case dev_xfer:
789*4f2df630SAndroid Build Coastguard Worker done = write(td->tpm_fd, out, len);
790*4f2df630SAndroid Build Coastguard Worker break;
791*4f2df630SAndroid Build Coastguard Worker case ts_xfer:
792*4f2df630SAndroid Build Coastguard Worker done = ts_write(out, len);
793*4f2df630SAndroid Build Coastguard Worker break;
794*4f2df630SAndroid Build Coastguard Worker default:
795*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: %s:%d: unknown transfer type %d\n",
796*4f2df630SAndroid Build Coastguard Worker __func__, __LINE__, td->ep_type);
797*4f2df630SAndroid Build Coastguard Worker return -1;
798*4f2df630SAndroid Build Coastguard Worker }
799*4f2df630SAndroid Build Coastguard Worker
800*4f2df630SAndroid Build Coastguard Worker if (done < 0) {
801*4f2df630SAndroid Build Coastguard Worker perror("Could not write to TPM");
802*4f2df630SAndroid Build Coastguard Worker return -1;
803*4f2df630SAndroid Build Coastguard Worker } else if (done != len) {
804*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: Wrote %d bytes, expected to write %d\n",
805*4f2df630SAndroid Build Coastguard Worker done, len);
806*4f2df630SAndroid Build Coastguard Worker return -1;
807*4f2df630SAndroid Build Coastguard Worker }
808*4f2df630SAndroid Build Coastguard Worker
809*4f2df630SAndroid Build Coastguard Worker switch (td->ep_type) {
810*4f2df630SAndroid Build Coastguard Worker case dev_xfer: {
811*4f2df630SAndroid Build Coastguard Worker int read_count;
812*4f2df630SAndroid Build Coastguard Worker
813*4f2df630SAndroid Build Coastguard Worker len = 0;
814*4f2df630SAndroid Build Coastguard Worker do {
815*4f2df630SAndroid Build Coastguard Worker uint8_t *rx_buf = raw_response + len;
816*4f2df630SAndroid Build Coastguard Worker size_t rx_to_go = rx_size - len;
817*4f2df630SAndroid Build Coastguard Worker
818*4f2df630SAndroid Build Coastguard Worker read_count = read(td->tpm_fd, rx_buf, rx_to_go);
819*4f2df630SAndroid Build Coastguard Worker
820*4f2df630SAndroid Build Coastguard Worker len += read_count;
821*4f2df630SAndroid Build Coastguard Worker } while (read_count);
822*4f2df630SAndroid Build Coastguard Worker break;
823*4f2df630SAndroid Build Coastguard Worker }
824*4f2df630SAndroid Build Coastguard Worker case ts_xfer:
825*4f2df630SAndroid Build Coastguard Worker len = ts_read(raw_response, rx_size);
826*4f2df630SAndroid Build Coastguard Worker break;
827*4f2df630SAndroid Build Coastguard Worker default:
828*4f2df630SAndroid Build Coastguard Worker /*
829*4f2df630SAndroid Build Coastguard Worker * This sure will never happen, type is verifed in the
830*4f2df630SAndroid Build Coastguard Worker * previous switch statement.
831*4f2df630SAndroid Build Coastguard Worker */
832*4f2df630SAndroid Build Coastguard Worker len = -1;
833*4f2df630SAndroid Build Coastguard Worker break;
834*4f2df630SAndroid Build Coastguard Worker }
835*4f2df630SAndroid Build Coastguard Worker
836*4f2df630SAndroid Build Coastguard Worker debug("Read %d bytes from TPM\n", len);
837*4f2df630SAndroid Build Coastguard Worker if (len > 0) {
838*4f2df630SAndroid Build Coastguard Worker int i;
839*4f2df630SAndroid Build Coastguard Worker
840*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < len; i++)
841*4f2df630SAndroid Build Coastguard Worker debug("%2.2x ", raw_response[i]);
842*4f2df630SAndroid Build Coastguard Worker debug("\n");
843*4f2df630SAndroid Build Coastguard Worker }
844*4f2df630SAndroid Build Coastguard Worker len = len - response_offset;
845*4f2df630SAndroid Build Coastguard Worker if (len < 0) {
846*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Problems reading from TPM, got %d bytes\n",
847*4f2df630SAndroid Build Coastguard Worker len + response_offset);
848*4f2df630SAndroid Build Coastguard Worker return -1;
849*4f2df630SAndroid Build Coastguard Worker }
850*4f2df630SAndroid Build Coastguard Worker
851*4f2df630SAndroid Build Coastguard Worker if (response && response_size) {
852*4f2df630SAndroid Build Coastguard Worker len = MIN(len, *response_size);
853*4f2df630SAndroid Build Coastguard Worker memcpy(response, raw_response + response_offset, len);
854*4f2df630SAndroid Build Coastguard Worker *response_size = len;
855*4f2df630SAndroid Build Coastguard Worker }
856*4f2df630SAndroid Build Coastguard Worker
857*4f2df630SAndroid Build Coastguard Worker /* Return the actual return code from the TPM response header. */
858*4f2df630SAndroid Build Coastguard Worker memcpy(&rv, &((struct upgrade_pkt *)raw_response)->ordinal, sizeof(rv));
859*4f2df630SAndroid Build Coastguard Worker rv = be32toh(rv);
860*4f2df630SAndroid Build Coastguard Worker
861*4f2df630SAndroid Build Coastguard Worker /* Clear out vendor command return value offset.*/
862*4f2df630SAndroid Build Coastguard Worker if ((rv & VENDOR_RC_ERR) == VENDOR_RC_ERR)
863*4f2df630SAndroid Build Coastguard Worker rv &= ~VENDOR_RC_ERR;
864*4f2df630SAndroid Build Coastguard Worker
865*4f2df630SAndroid Build Coastguard Worker return rv;
866*4f2df630SAndroid Build Coastguard Worker }
867*4f2df630SAndroid Build Coastguard Worker
868*4f2df630SAndroid Build Coastguard Worker /* Release USB device and return error to the OS. */
shut_down(struct usb_endpoint * uep)869*4f2df630SAndroid Build Coastguard Worker static void shut_down(struct usb_endpoint *uep)
870*4f2df630SAndroid Build Coastguard Worker {
871*4f2df630SAndroid Build Coastguard Worker usb_shut_down(uep);
872*4f2df630SAndroid Build Coastguard Worker exit(update_error);
873*4f2df630SAndroid Build Coastguard Worker }
874*4f2df630SAndroid Build Coastguard Worker
usage(int errs)875*4f2df630SAndroid Build Coastguard Worker static void usage(int errs)
876*4f2df630SAndroid Build Coastguard Worker {
877*4f2df630SAndroid Build Coastguard Worker size_t i;
878*4f2df630SAndroid Build Coastguard Worker const int indent = 27; /* This is the size used by gsctool all along. */
879*4f2df630SAndroid Build Coastguard Worker
880*4f2df630SAndroid Build Coastguard Worker printf("\nUsage: %s [options] [<binary image>]\n"
881*4f2df630SAndroid Build Coastguard Worker "\n"
882*4f2df630SAndroid Build Coastguard Worker "This utility allows to update Cr50 RW firmware, configure\n"
883*4f2df630SAndroid Build Coastguard Worker "various aspects of Cr50 operation, analyze Cr50 binary\n"
884*4f2df630SAndroid Build Coastguard Worker "images, etc.\n\n"
885*4f2df630SAndroid Build Coastguard Worker "<binary image> is the file name of a full RO+RW binary image.\n"
886*4f2df630SAndroid Build Coastguard Worker "\n"
887*4f2df630SAndroid Build Coastguard Worker "Options:\n\n",
888*4f2df630SAndroid Build Coastguard Worker progname);
889*4f2df630SAndroid Build Coastguard Worker
890*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(cmd_line_options); i++) {
891*4f2df630SAndroid Build Coastguard Worker const char *help_text = cmd_line_options[i].help_text;
892*4f2df630SAndroid Build Coastguard Worker int printed_length;
893*4f2df630SAndroid Build Coastguard Worker const char *separator;
894*4f2df630SAndroid Build Coastguard Worker
895*4f2df630SAndroid Build Coastguard Worker /*
896*4f2df630SAndroid Build Coastguard Worker * First print the short and long forms of the command line
897*4f2df630SAndroid Build Coastguard Worker * option.
898*4f2df630SAndroid Build Coastguard Worker */
899*4f2df630SAndroid Build Coastguard Worker printed_length = printf(" -%c,--%s",
900*4f2df630SAndroid Build Coastguard Worker cmd_line_options[i].opt.val,
901*4f2df630SAndroid Build Coastguard Worker cmd_line_options[i].opt.name);
902*4f2df630SAndroid Build Coastguard Worker
903*4f2df630SAndroid Build Coastguard Worker /*
904*4f2df630SAndroid Build Coastguard Worker * If there is something to print immediately after the
905*4f2df630SAndroid Build Coastguard Worker * options, print it.
906*4f2df630SAndroid Build Coastguard Worker */
907*4f2df630SAndroid Build Coastguard Worker separator = strchr(help_text, '%');
908*4f2df630SAndroid Build Coastguard Worker if (separator) {
909*4f2df630SAndroid Build Coastguard Worker char buffer[80];
910*4f2df630SAndroid Build Coastguard Worker size_t extra_size;
911*4f2df630SAndroid Build Coastguard Worker
912*4f2df630SAndroid Build Coastguard Worker extra_size = separator - help_text;
913*4f2df630SAndroid Build Coastguard Worker if (extra_size >= sizeof(buffer)) {
914*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "misformatted help text: %s\n",
915*4f2df630SAndroid Build Coastguard Worker help_text);
916*4f2df630SAndroid Build Coastguard Worker exit(-1);
917*4f2df630SAndroid Build Coastguard Worker }
918*4f2df630SAndroid Build Coastguard Worker memcpy(buffer, help_text, extra_size);
919*4f2df630SAndroid Build Coastguard Worker buffer[extra_size] = '\0';
920*4f2df630SAndroid Build Coastguard Worker printed_length += printf(" %s", buffer);
921*4f2df630SAndroid Build Coastguard Worker help_text = separator + 1;
922*4f2df630SAndroid Build Coastguard Worker }
923*4f2df630SAndroid Build Coastguard Worker
924*4f2df630SAndroid Build Coastguard Worker /*
925*4f2df630SAndroid Build Coastguard Worker * If printed length exceeds or is too close to indent, print
926*4f2df630SAndroid Build Coastguard Worker * help text on the next line.
927*4f2df630SAndroid Build Coastguard Worker */
928*4f2df630SAndroid Build Coastguard Worker if (printed_length >= (indent - 1)) {
929*4f2df630SAndroid Build Coastguard Worker printf("\n");
930*4f2df630SAndroid Build Coastguard Worker printed_length = 0;
931*4f2df630SAndroid Build Coastguard Worker }
932*4f2df630SAndroid Build Coastguard Worker
933*4f2df630SAndroid Build Coastguard Worker while (printed_length++ < indent)
934*4f2df630SAndroid Build Coastguard Worker printf(" ");
935*4f2df630SAndroid Build Coastguard Worker printf("%s\n", help_text);
936*4f2df630SAndroid Build Coastguard Worker }
937*4f2df630SAndroid Build Coastguard Worker printf("\n");
938*4f2df630SAndroid Build Coastguard Worker exit(errs ? update_error : noop);
939*4f2df630SAndroid Build Coastguard Worker }
940*4f2df630SAndroid Build Coastguard Worker
941*4f2df630SAndroid Build Coastguard Worker /* Read file into buffer */
get_file_or_die(const char * filename,size_t * len_ptr)942*4f2df630SAndroid Build Coastguard Worker static uint8_t *get_file_or_die(const char *filename, size_t *len_ptr)
943*4f2df630SAndroid Build Coastguard Worker {
944*4f2df630SAndroid Build Coastguard Worker FILE *fp;
945*4f2df630SAndroid Build Coastguard Worker struct stat st;
946*4f2df630SAndroid Build Coastguard Worker uint8_t *data;
947*4f2df630SAndroid Build Coastguard Worker size_t len;
948*4f2df630SAndroid Build Coastguard Worker
949*4f2df630SAndroid Build Coastguard Worker fp = fopen(filename, "rb");
950*4f2df630SAndroid Build Coastguard Worker if (!fp) {
951*4f2df630SAndroid Build Coastguard Worker perror(filename);
952*4f2df630SAndroid Build Coastguard Worker exit(update_error);
953*4f2df630SAndroid Build Coastguard Worker }
954*4f2df630SAndroid Build Coastguard Worker if (fstat(fileno(fp), &st)) {
955*4f2df630SAndroid Build Coastguard Worker perror("stat");
956*4f2df630SAndroid Build Coastguard Worker exit(update_error);
957*4f2df630SAndroid Build Coastguard Worker }
958*4f2df630SAndroid Build Coastguard Worker
959*4f2df630SAndroid Build Coastguard Worker len = st.st_size;
960*4f2df630SAndroid Build Coastguard Worker
961*4f2df630SAndroid Build Coastguard Worker data = malloc(len);
962*4f2df630SAndroid Build Coastguard Worker if (!data) {
963*4f2df630SAndroid Build Coastguard Worker perror("malloc");
964*4f2df630SAndroid Build Coastguard Worker exit(update_error);
965*4f2df630SAndroid Build Coastguard Worker }
966*4f2df630SAndroid Build Coastguard Worker
967*4f2df630SAndroid Build Coastguard Worker if (1 != fread(data, st.st_size, 1, fp)) {
968*4f2df630SAndroid Build Coastguard Worker perror("fread");
969*4f2df630SAndroid Build Coastguard Worker exit(update_error);
970*4f2df630SAndroid Build Coastguard Worker }
971*4f2df630SAndroid Build Coastguard Worker
972*4f2df630SAndroid Build Coastguard Worker fclose(fp);
973*4f2df630SAndroid Build Coastguard Worker
974*4f2df630SAndroid Build Coastguard Worker *len_ptr = len;
975*4f2df630SAndroid Build Coastguard Worker return data;
976*4f2df630SAndroid Build Coastguard Worker }
977*4f2df630SAndroid Build Coastguard Worker
978*4f2df630SAndroid Build Coastguard Worker /* Returns true if parsed. */
parse_vidpid(const char * input,uint16_t * vid_ptr,uint16_t * pid_ptr)979*4f2df630SAndroid Build Coastguard Worker static int parse_vidpid(const char *input, uint16_t *vid_ptr, uint16_t *pid_ptr)
980*4f2df630SAndroid Build Coastguard Worker {
981*4f2df630SAndroid Build Coastguard Worker char *copy, *s, *e = 0;
982*4f2df630SAndroid Build Coastguard Worker
983*4f2df630SAndroid Build Coastguard Worker copy = strdup(input);
984*4f2df630SAndroid Build Coastguard Worker
985*4f2df630SAndroid Build Coastguard Worker s = strchr(copy, ':');
986*4f2df630SAndroid Build Coastguard Worker if (!s)
987*4f2df630SAndroid Build Coastguard Worker return 0;
988*4f2df630SAndroid Build Coastguard Worker *s++ = '\0';
989*4f2df630SAndroid Build Coastguard Worker
990*4f2df630SAndroid Build Coastguard Worker *vid_ptr = (uint16_t)strtoul(copy, &e, 16);
991*4f2df630SAndroid Build Coastguard Worker if (!*optarg || (e && *e))
992*4f2df630SAndroid Build Coastguard Worker return 0;
993*4f2df630SAndroid Build Coastguard Worker
994*4f2df630SAndroid Build Coastguard Worker *pid_ptr = (uint16_t)strtoul(s, &e, 16);
995*4f2df630SAndroid Build Coastguard Worker if (!*optarg || (e && *e))
996*4f2df630SAndroid Build Coastguard Worker return 0;
997*4f2df630SAndroid Build Coastguard Worker
998*4f2df630SAndroid Build Coastguard Worker return 1;
999*4f2df630SAndroid Build Coastguard Worker }
1000*4f2df630SAndroid Build Coastguard Worker
1001*4f2df630SAndroid Build Coastguard Worker struct update_pdu {
1002*4f2df630SAndroid Build Coastguard Worker uint32_t block_size; /* Total block size, include this field's size. */
1003*4f2df630SAndroid Build Coastguard Worker struct upgrade_command cmd;
1004*4f2df630SAndroid Build Coastguard Worker /* The actual payload goes here. */
1005*4f2df630SAndroid Build Coastguard Worker };
1006*4f2df630SAndroid Build Coastguard Worker
do_xfer(struct usb_endpoint * uep,void * outbuf,int outlen,void * inbuf,int inlen,int allow_less,size_t * rxed_count)1007*4f2df630SAndroid Build Coastguard Worker static void do_xfer(struct usb_endpoint *uep, void *outbuf, int outlen,
1008*4f2df630SAndroid Build Coastguard Worker void *inbuf, int inlen, int allow_less, size_t *rxed_count)
1009*4f2df630SAndroid Build Coastguard Worker {
1010*4f2df630SAndroid Build Coastguard Worker if (usb_trx(uep, outbuf, outlen, inbuf, inlen, allow_less, rxed_count))
1011*4f2df630SAndroid Build Coastguard Worker shut_down(uep);
1012*4f2df630SAndroid Build Coastguard Worker }
1013*4f2df630SAndroid Build Coastguard Worker
transfer_block(struct usb_endpoint * uep,struct update_pdu * updu,uint8_t * transfer_data_ptr,size_t payload_size)1014*4f2df630SAndroid Build Coastguard Worker static int transfer_block(struct usb_endpoint *uep, struct update_pdu *updu,
1015*4f2df630SAndroid Build Coastguard Worker uint8_t *transfer_data_ptr, size_t payload_size)
1016*4f2df630SAndroid Build Coastguard Worker {
1017*4f2df630SAndroid Build Coastguard Worker size_t transfer_size;
1018*4f2df630SAndroid Build Coastguard Worker uint32_t reply;
1019*4f2df630SAndroid Build Coastguard Worker int actual;
1020*4f2df630SAndroid Build Coastguard Worker int r;
1021*4f2df630SAndroid Build Coastguard Worker
1022*4f2df630SAndroid Build Coastguard Worker /* First send the header. */
1023*4f2df630SAndroid Build Coastguard Worker do_xfer(uep, updu, sizeof(*updu), NULL, 0, 0, NULL);
1024*4f2df630SAndroid Build Coastguard Worker
1025*4f2df630SAndroid Build Coastguard Worker /* Now send the block, chunk by chunk. */
1026*4f2df630SAndroid Build Coastguard Worker for (transfer_size = 0; transfer_size < payload_size;) {
1027*4f2df630SAndroid Build Coastguard Worker int chunk_size;
1028*4f2df630SAndroid Build Coastguard Worker
1029*4f2df630SAndroid Build Coastguard Worker chunk_size = MIN(uep->chunk_len, payload_size - transfer_size);
1030*4f2df630SAndroid Build Coastguard Worker do_xfer(uep, transfer_data_ptr, chunk_size, NULL, 0, 0, NULL);
1031*4f2df630SAndroid Build Coastguard Worker transfer_data_ptr += chunk_size;
1032*4f2df630SAndroid Build Coastguard Worker transfer_size += chunk_size;
1033*4f2df630SAndroid Build Coastguard Worker }
1034*4f2df630SAndroid Build Coastguard Worker
1035*4f2df630SAndroid Build Coastguard Worker /* Now get the reply. */
1036*4f2df630SAndroid Build Coastguard Worker r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80, (void *)&reply,
1037*4f2df630SAndroid Build Coastguard Worker sizeof(reply), &actual, 1000);
1038*4f2df630SAndroid Build Coastguard Worker if (r) {
1039*4f2df630SAndroid Build Coastguard Worker if (r == -7) {
1040*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Timeout!\n");
1041*4f2df630SAndroid Build Coastguard Worker return r;
1042*4f2df630SAndroid Build Coastguard Worker }
1043*4f2df630SAndroid Build Coastguard Worker USB_ERROR("libusb_bulk_transfer", r);
1044*4f2df630SAndroid Build Coastguard Worker shut_down(uep);
1045*4f2df630SAndroid Build Coastguard Worker }
1046*4f2df630SAndroid Build Coastguard Worker
1047*4f2df630SAndroid Build Coastguard Worker reply = *((uint8_t *)&reply);
1048*4f2df630SAndroid Build Coastguard Worker if (reply) {
1049*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: status %#x\n", reply);
1050*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1051*4f2df630SAndroid Build Coastguard Worker }
1052*4f2df630SAndroid Build Coastguard Worker
1053*4f2df630SAndroid Build Coastguard Worker return 0;
1054*4f2df630SAndroid Build Coastguard Worker }
1055*4f2df630SAndroid Build Coastguard Worker
1056*4f2df630SAndroid Build Coastguard Worker /**
1057*4f2df630SAndroid Build Coastguard Worker * Transfer an image section (typically RW or RO).
1058*4f2df630SAndroid Build Coastguard Worker *
1059*4f2df630SAndroid Build Coastguard Worker * td - transfer descriptor to use to communicate with the target
1060*4f2df630SAndroid Build Coastguard Worker * data_ptr - pointer at the section base in the image
1061*4f2df630SAndroid Build Coastguard Worker * section_addr - address of the section in the target memory space
1062*4f2df630SAndroid Build Coastguard Worker * data_len - section size
1063*4f2df630SAndroid Build Coastguard Worker */
transfer_section(struct transfer_descriptor * td,uint8_t * data_ptr,uint32_t section_addr,size_t data_len)1064*4f2df630SAndroid Build Coastguard Worker static void transfer_section(struct transfer_descriptor *td, uint8_t *data_ptr,
1065*4f2df630SAndroid Build Coastguard Worker uint32_t section_addr, size_t data_len)
1066*4f2df630SAndroid Build Coastguard Worker {
1067*4f2df630SAndroid Build Coastguard Worker /*
1068*4f2df630SAndroid Build Coastguard Worker * Actually, we can skip trailing chunks of 0xff, as the entire
1069*4f2df630SAndroid Build Coastguard Worker * section space must be erased before the update is attempted.
1070*4f2df630SAndroid Build Coastguard Worker */
1071*4f2df630SAndroid Build Coastguard Worker while (data_len && (data_ptr[data_len - 1] == 0xff))
1072*4f2df630SAndroid Build Coastguard Worker data_len--;
1073*4f2df630SAndroid Build Coastguard Worker
1074*4f2df630SAndroid Build Coastguard Worker /*
1075*4f2df630SAndroid Build Coastguard Worker * Make sure total size is 4 bytes aligned, this is required for
1076*4f2df630SAndroid Build Coastguard Worker * successful flashing.
1077*4f2df630SAndroid Build Coastguard Worker */
1078*4f2df630SAndroid Build Coastguard Worker data_len = (data_len + 3) & ~3;
1079*4f2df630SAndroid Build Coastguard Worker
1080*4f2df630SAndroid Build Coastguard Worker printf("sending 0x%zx bytes to %#x\n", data_len, section_addr);
1081*4f2df630SAndroid Build Coastguard Worker while (data_len) {
1082*4f2df630SAndroid Build Coastguard Worker size_t payload_size;
1083*4f2df630SAndroid Build Coastguard Worker EVP_MD_CTX *ctx;
1084*4f2df630SAndroid Build Coastguard Worker int max_retries;
1085*4f2df630SAndroid Build Coastguard Worker struct update_pdu updu;
1086*4f2df630SAndroid Build Coastguard Worker
1087*4f2df630SAndroid Build Coastguard Worker /* prepare the header to prepend to the block. */
1088*4f2df630SAndroid Build Coastguard Worker payload_size = MIN(data_len, SIGNED_TRANSFER_SIZE);
1089*4f2df630SAndroid Build Coastguard Worker updu.block_size =
1090*4f2df630SAndroid Build Coastguard Worker htobe32(payload_size + sizeof(struct update_pdu));
1091*4f2df630SAndroid Build Coastguard Worker
1092*4f2df630SAndroid Build Coastguard Worker updu.cmd.block_base = htobe32(section_addr);
1093*4f2df630SAndroid Build Coastguard Worker
1094*4f2df630SAndroid Build Coastguard Worker /* Calculate the digest. */
1095*4f2df630SAndroid Build Coastguard Worker ctx = EVP_MD_CTX_new();
1096*4f2df630SAndroid Build Coastguard Worker sha_init(ctx);
1097*4f2df630SAndroid Build Coastguard Worker sha_update(ctx, &updu.cmd.block_base,
1098*4f2df630SAndroid Build Coastguard Worker sizeof(updu.cmd.block_base));
1099*4f2df630SAndroid Build Coastguard Worker sha_update(ctx, data_ptr, payload_size);
1100*4f2df630SAndroid Build Coastguard Worker sha_final_into_block_digest(ctx, &updu.cmd.block_digest,
1101*4f2df630SAndroid Build Coastguard Worker sizeof(updu.cmd.block_digest));
1102*4f2df630SAndroid Build Coastguard Worker EVP_MD_CTX_free(ctx);
1103*4f2df630SAndroid Build Coastguard Worker
1104*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer) {
1105*4f2df630SAndroid Build Coastguard Worker for (max_retries = 10; max_retries; max_retries--)
1106*4f2df630SAndroid Build Coastguard Worker if (!transfer_block(&td->uep, &updu, data_ptr,
1107*4f2df630SAndroid Build Coastguard Worker payload_size))
1108*4f2df630SAndroid Build Coastguard Worker break;
1109*4f2df630SAndroid Build Coastguard Worker
1110*4f2df630SAndroid Build Coastguard Worker if (!max_retries) {
1111*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
1112*4f2df630SAndroid Build Coastguard Worker "Failed to transfer block, %zd to go\n",
1113*4f2df630SAndroid Build Coastguard Worker data_len);
1114*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1115*4f2df630SAndroid Build Coastguard Worker }
1116*4f2df630SAndroid Build Coastguard Worker } else {
1117*4f2df630SAndroid Build Coastguard Worker uint8_t error_code[4];
1118*4f2df630SAndroid Build Coastguard Worker size_t rxed_size = sizeof(error_code);
1119*4f2df630SAndroid Build Coastguard Worker uint32_t block_addr;
1120*4f2df630SAndroid Build Coastguard Worker
1121*4f2df630SAndroid Build Coastguard Worker block_addr = section_addr;
1122*4f2df630SAndroid Build Coastguard Worker
1123*4f2df630SAndroid Build Coastguard Worker /*
1124*4f2df630SAndroid Build Coastguard Worker * A single byte response is expected, but let's give
1125*4f2df630SAndroid Build Coastguard Worker * the driver a few extra bytes to catch cases when a
1126*4f2df630SAndroid Build Coastguard Worker * different amount of data is transferred (which
1127*4f2df630SAndroid Build Coastguard Worker * would indicate a synchronization problem).
1128*4f2df630SAndroid Build Coastguard Worker */
1129*4f2df630SAndroid Build Coastguard Worker if (tpm_send_pkt(td, updu.cmd.block_digest, block_addr,
1130*4f2df630SAndroid Build Coastguard Worker data_ptr, payload_size, error_code,
1131*4f2df630SAndroid Build Coastguard Worker &rxed_size,
1132*4f2df630SAndroid Build Coastguard Worker EXTENSION_FW_UPGRADE) < 0) {
1133*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
1134*4f2df630SAndroid Build Coastguard Worker "Failed to trasfer block, %zd to go\n",
1135*4f2df630SAndroid Build Coastguard Worker data_len);
1136*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1137*4f2df630SAndroid Build Coastguard Worker }
1138*4f2df630SAndroid Build Coastguard Worker if (rxed_size != 1) {
1139*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected return size %zd\n",
1140*4f2df630SAndroid Build Coastguard Worker rxed_size);
1141*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1142*4f2df630SAndroid Build Coastguard Worker }
1143*4f2df630SAndroid Build Coastguard Worker
1144*4f2df630SAndroid Build Coastguard Worker if (error_code[0]) {
1145*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d\n", error_code[0]);
1146*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1147*4f2df630SAndroid Build Coastguard Worker }
1148*4f2df630SAndroid Build Coastguard Worker }
1149*4f2df630SAndroid Build Coastguard Worker data_len -= payload_size;
1150*4f2df630SAndroid Build Coastguard Worker data_ptr += payload_size;
1151*4f2df630SAndroid Build Coastguard Worker section_addr += payload_size;
1152*4f2df630SAndroid Build Coastguard Worker }
1153*4f2df630SAndroid Build Coastguard Worker }
1154*4f2df630SAndroid Build Coastguard Worker
1155*4f2df630SAndroid Build Coastguard Worker /* Information about the target */
1156*4f2df630SAndroid Build Coastguard Worker static struct first_response_pdu targ;
1157*4f2df630SAndroid Build Coastguard Worker
1158*4f2df630SAndroid Build Coastguard Worker /* The well known CR50 section location and sizes. These are not scanned for. */
1159*4f2df630SAndroid Build Coastguard Worker const struct section_t CR50_SECTIONS[NUM_SECTIONS] = {
1160*4f2df630SAndroid Build Coastguard Worker [RO_A] = { CONFIG_RO_MEM_OFF, CONFIG_RO_SIZE },
1161*4f2df630SAndroid Build Coastguard Worker [RW_A] = { CONFIG_RW_MEM_OFF, CONFIG_RW_SIZE },
1162*4f2df630SAndroid Build Coastguard Worker [RO_B] = { CHIP_RO_B_MEM_OFF, CONFIG_RO_SIZE },
1163*4f2df630SAndroid Build Coastguard Worker [RW_B] = { CONFIG_RW_B_MEM_OFF, CONFIG_RW_SIZE }
1164*4f2df630SAndroid Build Coastguard Worker };
1165*4f2df630SAndroid Build Coastguard Worker
1166*4f2df630SAndroid Build Coastguard Worker /*
1167*4f2df630SAndroid Build Coastguard Worker * Remove these definitions so a developer doesn't accidentally use them in
1168*4f2df630SAndroid Build Coastguard Worker * the future. All lookups should go through the sections array.
1169*4f2df630SAndroid Build Coastguard Worker */
1170*4f2df630SAndroid Build Coastguard Worker #undef CONFIG_RO_MEM_OFF
1171*4f2df630SAndroid Build Coastguard Worker #undef CONFIG_RW_MEM_OFF
1172*4f2df630SAndroid Build Coastguard Worker #undef CHIP_RO_B_MEM_OFF
1173*4f2df630SAndroid Build Coastguard Worker #undef CONFIG_RW_B_MEM_OFF
1174*4f2df630SAndroid Build Coastguard Worker #undef CONFIG_RO_SIZE
1175*4f2df630SAndroid Build Coastguard Worker #undef CONFIG_RW_SIZE
1176*4f2df630SAndroid Build Coastguard Worker #undef CONFIG_FLASH_SIZE
1177*4f2df630SAndroid Build Coastguard Worker
1178*4f2df630SAndroid Build Coastguard Worker /* Returns true if the specified signed header is valid */
valid_signed_header(const struct SignedHeader * const h,const size_t size)1179*4f2df630SAndroid Build Coastguard Worker static bool valid_signed_header(const struct SignedHeader *const h,
1180*4f2df630SAndroid Build Coastguard Worker const size_t size)
1181*4f2df630SAndroid Build Coastguard Worker {
1182*4f2df630SAndroid Build Coastguard Worker if (size < sizeof(struct SignedHeader))
1183*4f2df630SAndroid Build Coastguard Worker return false;
1184*4f2df630SAndroid Build Coastguard Worker
1185*4f2df630SAndroid Build Coastguard Worker /* Only H1 and D2 are currently supported. */
1186*4f2df630SAndroid Build Coastguard Worker if (h->magic != MAGIC_HAVEN && h->magic != MAGIC_DAUNTLESS)
1187*4f2df630SAndroid Build Coastguard Worker return false;
1188*4f2df630SAndroid Build Coastguard Worker
1189*4f2df630SAndroid Build Coastguard Worker if (h->image_size > size)
1190*4f2df630SAndroid Build Coastguard Worker return false;
1191*4f2df630SAndroid Build Coastguard Worker
1192*4f2df630SAndroid Build Coastguard Worker if (h->image_size < CONFIG_FLASH_BANK_SIZE)
1193*4f2df630SAndroid Build Coastguard Worker return false;
1194*4f2df630SAndroid Build Coastguard Worker
1195*4f2df630SAndroid Build Coastguard Worker /*
1196*4f2df630SAndroid Build Coastguard Worker * Both Rx base and Ro base are the memory mapped address, but they
1197*4f2df630SAndroid Build Coastguard Worker * should have the same offset. The rx section starts after the header.
1198*4f2df630SAndroid Build Coastguard Worker */
1199*4f2df630SAndroid Build Coastguard Worker if (h->rx_base != h->ro_base + sizeof(struct SignedHeader))
1200*4f2df630SAndroid Build Coastguard Worker return false;
1201*4f2df630SAndroid Build Coastguard Worker
1202*4f2df630SAndroid Build Coastguard Worker /* Ensure each section falls within full size */
1203*4f2df630SAndroid Build Coastguard Worker if (h->ro_max - h->ro_base > size)
1204*4f2df630SAndroid Build Coastguard Worker return false;
1205*4f2df630SAndroid Build Coastguard Worker
1206*4f2df630SAndroid Build Coastguard Worker if (h->rx_max - h->rx_base > size)
1207*4f2df630SAndroid Build Coastguard Worker return false;
1208*4f2df630SAndroid Build Coastguard Worker
1209*4f2df630SAndroid Build Coastguard Worker return true;
1210*4f2df630SAndroid Build Coastguard Worker }
1211*4f2df630SAndroid Build Coastguard Worker
1212*4f2df630SAndroid Build Coastguard Worker /* Returns true if the specified opentitan manifest header is valid */
valid_nt_manifest(const struct SignedManifest * const m,const size_t size)1213*4f2df630SAndroid Build Coastguard Worker static bool valid_nt_manifest(const struct SignedManifest *const m,
1214*4f2df630SAndroid Build Coastguard Worker const size_t size)
1215*4f2df630SAndroid Build Coastguard Worker {
1216*4f2df630SAndroid Build Coastguard Worker if (size < sizeof(struct SignedManifest))
1217*4f2df630SAndroid Build Coastguard Worker return false;
1218*4f2df630SAndroid Build Coastguard Worker
1219*4f2df630SAndroid Build Coastguard Worker if (m->identifier != ID_ROM_EXT && m->identifier != ID_OWNER_FW)
1220*4f2df630SAndroid Build Coastguard Worker return false;
1221*4f2df630SAndroid Build Coastguard Worker
1222*4f2df630SAndroid Build Coastguard Worker if (m->length > size)
1223*4f2df630SAndroid Build Coastguard Worker return false;
1224*4f2df630SAndroid Build Coastguard Worker
1225*4f2df630SAndroid Build Coastguard Worker if (m->code_start > m->code_end)
1226*4f2df630SAndroid Build Coastguard Worker return false;
1227*4f2df630SAndroid Build Coastguard Worker
1228*4f2df630SAndroid Build Coastguard Worker if (m->code_start > m->length)
1229*4f2df630SAndroid Build Coastguard Worker return false;
1230*4f2df630SAndroid Build Coastguard Worker
1231*4f2df630SAndroid Build Coastguard Worker if (m->code_end > m->length)
1232*4f2df630SAndroid Build Coastguard Worker return false;
1233*4f2df630SAndroid Build Coastguard Worker
1234*4f2df630SAndroid Build Coastguard Worker if (m->entry_point > m->code_end)
1235*4f2df630SAndroid Build Coastguard Worker return false;
1236*4f2df630SAndroid Build Coastguard Worker
1237*4f2df630SAndroid Build Coastguard Worker if (m->entry_point < m->code_start)
1238*4f2df630SAndroid Build Coastguard Worker return false;
1239*4f2df630SAndroid Build Coastguard Worker
1240*4f2df630SAndroid Build Coastguard Worker return true;
1241*4f2df630SAndroid Build Coastguard Worker }
1242*4f2df630SAndroid Build Coastguard Worker
1243*4f2df630SAndroid Build Coastguard Worker /* Returns true if the specified image header is valid */
valid_image_header(const struct typed_image_header h,const size_t size,enum gsc_device * out_device)1244*4f2df630SAndroid Build Coastguard Worker static bool valid_image_header(const struct typed_image_header h,
1245*4f2df630SAndroid Build Coastguard Worker const size_t size, enum gsc_device *out_device)
1246*4f2df630SAndroid Build Coastguard Worker {
1247*4f2df630SAndroid Build Coastguard Worker if (valid_nt_manifest(h.m, size)) {
1248*4f2df630SAndroid Build Coastguard Worker enum gsc_device type = GSC_DEVICE_NT;
1249*4f2df630SAndroid Build Coastguard Worker
1250*4f2df630SAndroid Build Coastguard Worker if (out_device) {
1251*4f2df630SAndroid Build Coastguard Worker *out_device = type;
1252*4f2df630SAndroid Build Coastguard Worker return true;
1253*4f2df630SAndroid Build Coastguard Worker } else {
1254*4f2df630SAndroid Build Coastguard Worker return h.type == type;
1255*4f2df630SAndroid Build Coastguard Worker }
1256*4f2df630SAndroid Build Coastguard Worker }
1257*4f2df630SAndroid Build Coastguard Worker if (valid_signed_header(h.h, size)) {
1258*4f2df630SAndroid Build Coastguard Worker enum gsc_device type = GSC_DEVICE_H1;
1259*4f2df630SAndroid Build Coastguard Worker
1260*4f2df630SAndroid Build Coastguard Worker if (h.h->magic == MAGIC_DAUNTLESS) {
1261*4f2df630SAndroid Build Coastguard Worker type = GSC_DEVICE_DT;
1262*4f2df630SAndroid Build Coastguard Worker } else if (h.h->magic != MAGIC_HAVEN) {
1263*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
1264*4f2df630SAndroid Build Coastguard Worker "Error: Cannot determine image type.\n");
1265*4f2df630SAndroid Build Coastguard Worker /* Unsupported image type */
1266*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1267*4f2df630SAndroid Build Coastguard Worker }
1268*4f2df630SAndroid Build Coastguard Worker if (out_device) {
1269*4f2df630SAndroid Build Coastguard Worker *out_device = type;
1270*4f2df630SAndroid Build Coastguard Worker return true;
1271*4f2df630SAndroid Build Coastguard Worker } else {
1272*4f2df630SAndroid Build Coastguard Worker return h.type == type;
1273*4f2df630SAndroid Build Coastguard Worker }
1274*4f2df630SAndroid Build Coastguard Worker }
1275*4f2df630SAndroid Build Coastguard Worker return false;
1276*4f2df630SAndroid Build Coastguard Worker }
1277*4f2df630SAndroid Build Coastguard Worker
1278*4f2df630SAndroid Build Coastguard Worker /* Returns the image size from the header. This assumes it is valid */
get_size_from_header(const struct typed_image_header h)1279*4f2df630SAndroid Build Coastguard Worker static uint32_t get_size_from_header(const struct typed_image_header h)
1280*4f2df630SAndroid Build Coastguard Worker {
1281*4f2df630SAndroid Build Coastguard Worker if (h.type == GSC_DEVICE_H1 || h.type == GSC_DEVICE_DT)
1282*4f2df630SAndroid Build Coastguard Worker return h.h->image_size;
1283*4f2df630SAndroid Build Coastguard Worker
1284*4f2df630SAndroid Build Coastguard Worker if (h.type == GSC_DEVICE_NT)
1285*4f2df630SAndroid Build Coastguard Worker return h.m->length;
1286*4f2df630SAndroid Build Coastguard Worker
1287*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: Cannot determine image type.\n");
1288*4f2df630SAndroid Build Coastguard Worker /* Unsupported image type */
1289*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1290*4f2df630SAndroid Build Coastguard Worker return 0;
1291*4f2df630SAndroid Build Coastguard Worker }
1292*4f2df630SAndroid Build Coastguard Worker
1293*4f2df630SAndroid Build Coastguard Worker /* Rounds and address up to the next 2KB boundary if not one already */
round_up_2kb(const uint32_t addr)1294*4f2df630SAndroid Build Coastguard Worker static inline uint32_t round_up_2kb(const uint32_t addr)
1295*4f2df630SAndroid Build Coastguard Worker {
1296*4f2df630SAndroid Build Coastguard Worker const uint32_t mask = (2 * 1024) - 1;
1297*4f2df630SAndroid Build Coastguard Worker
1298*4f2df630SAndroid Build Coastguard Worker return (addr + mask) & ~mask;
1299*4f2df630SAndroid Build Coastguard Worker }
1300*4f2df630SAndroid Build Coastguard Worker
as_header(const struct image * image,uint32_t offset)1301*4f2df630SAndroid Build Coastguard Worker static struct typed_image_header as_header(const struct image *image,
1302*4f2df630SAndroid Build Coastguard Worker uint32_t offset)
1303*4f2df630SAndroid Build Coastguard Worker {
1304*4f2df630SAndroid Build Coastguard Worker struct typed_image_header ret = {
1305*4f2df630SAndroid Build Coastguard Worker image->type,
1306*4f2df630SAndroid Build Coastguard Worker { (void *)((uintptr_t)image->data + offset) },
1307*4f2df630SAndroid Build Coastguard Worker };
1308*4f2df630SAndroid Build Coastguard Worker return ret;
1309*4f2df630SAndroid Build Coastguard Worker }
1310*4f2df630SAndroid Build Coastguard Worker
1311*4f2df630SAndroid Build Coastguard Worker /* Returns the RW header or -1 if one cannot be found */
find_rw_header(const struct image * image,uint32_t offset,const uint32_t end)1312*4f2df630SAndroid Build Coastguard Worker static int32_t find_rw_header(const struct image *image, uint32_t offset,
1313*4f2df630SAndroid Build Coastguard Worker const uint32_t end)
1314*4f2df630SAndroid Build Coastguard Worker {
1315*4f2df630SAndroid Build Coastguard Worker offset = round_up_2kb(offset);
1316*4f2df630SAndroid Build Coastguard Worker
1317*4f2df630SAndroid Build Coastguard Worker while (offset < end) {
1318*4f2df630SAndroid Build Coastguard Worker if (valid_image_header(as_header(image, offset), end - offset,
1319*4f2df630SAndroid Build Coastguard Worker NULL))
1320*4f2df630SAndroid Build Coastguard Worker return offset;
1321*4f2df630SAndroid Build Coastguard Worker offset = round_up_2kb(offset + 1);
1322*4f2df630SAndroid Build Coastguard Worker }
1323*4f2df630SAndroid Build Coastguard Worker
1324*4f2df630SAndroid Build Coastguard Worker return -1;
1325*4f2df630SAndroid Build Coastguard Worker }
1326*4f2df630SAndroid Build Coastguard Worker
1327*4f2df630SAndroid Build Coastguard Worker /* Return true if we located headers and set sections correctly */
locate_headers(struct image * image)1328*4f2df630SAndroid Build Coastguard Worker static bool locate_headers(struct image *image)
1329*4f2df630SAndroid Build Coastguard Worker {
1330*4f2df630SAndroid Build Coastguard Worker const uint32_t slot_a_end = image->data_len / 2;
1331*4f2df630SAndroid Build Coastguard Worker struct section_t *sections = image->sections;
1332*4f2df630SAndroid Build Coastguard Worker int32_t rw_offset;
1333*4f2df630SAndroid Build Coastguard Worker
1334*4f2df630SAndroid Build Coastguard Worker /*
1335*4f2df630SAndroid Build Coastguard Worker * We assume that all 512KB images are "valid" H1 images. The DBG images
1336*4f2df630SAndroid Build Coastguard Worker * from the signer do not set the magic to -1 and no not set valid
1337*4f2df630SAndroid Build Coastguard Worker * section offsets. We do not want to break this case as it is used in
1338*4f2df630SAndroid Build Coastguard Worker * testing. The H1 offsets are also static, so we don't need to scan
1339*4f2df630SAndroid Build Coastguard Worker * for RW headers.
1340*4f2df630SAndroid Build Coastguard Worker */
1341*4f2df630SAndroid Build Coastguard Worker if (image->data_len == (512 * 1024)) {
1342*4f2df630SAndroid Build Coastguard Worker image->type = GSC_DEVICE_H1;
1343*4f2df630SAndroid Build Coastguard Worker memcpy(sections, CR50_SECTIONS, sizeof(CR50_SECTIONS));
1344*4f2df630SAndroid Build Coastguard Worker return true;
1345*4f2df630SAndroid Build Coastguard Worker }
1346*4f2df630SAndroid Build Coastguard Worker
1347*4f2df630SAndroid Build Coastguard Worker /*
1348*4f2df630SAndroid Build Coastguard Worker * We know that all other image types supported (i.e. Dauntless,
1349*4f2df630SAndroid Build Coastguard Worker * NuvoTitan) are 1MB in size.
1350*4f2df630SAndroid Build Coastguard Worker */
1351*4f2df630SAndroid Build Coastguard Worker if (image->data_len != (1024 * 1024)) {
1352*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: Image size (%zd KB) is invalid\n",
1353*4f2df630SAndroid Build Coastguard Worker image->data_len / 1024);
1354*4f2df630SAndroid Build Coastguard Worker return false;
1355*4f2df630SAndroid Build Coastguard Worker }
1356*4f2df630SAndroid Build Coastguard Worker
1357*4f2df630SAndroid Build Coastguard Worker /* Validate the RO_A header */
1358*4f2df630SAndroid Build Coastguard Worker if (!valid_image_header(as_header(image, 0), slot_a_end,
1359*4f2df630SAndroid Build Coastguard Worker &image->type)) {
1360*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: RO_A header is invalid\n");
1361*4f2df630SAndroid Build Coastguard Worker return false;
1362*4f2df630SAndroid Build Coastguard Worker }
1363*4f2df630SAndroid Build Coastguard Worker
1364*4f2df630SAndroid Build Coastguard Worker sections[RO_A].offset = 0;
1365*4f2df630SAndroid Build Coastguard Worker sections[RO_A].size = get_size_from_header(as_header(image, 0));
1366*4f2df630SAndroid Build Coastguard Worker
1367*4f2df630SAndroid Build Coastguard Worker /* Find RW_A */
1368*4f2df630SAndroid Build Coastguard Worker rw_offset = find_rw_header(
1369*4f2df630SAndroid Build Coastguard Worker image, sections[RO_A].offset + sections[RO_A].size, slot_a_end);
1370*4f2df630SAndroid Build Coastguard Worker if (rw_offset == -1) {
1371*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: RW_A header cannot be found\n");
1372*4f2df630SAndroid Build Coastguard Worker return false;
1373*4f2df630SAndroid Build Coastguard Worker }
1374*4f2df630SAndroid Build Coastguard Worker sections[RW_A].offset = rw_offset;
1375*4f2df630SAndroid Build Coastguard Worker sections[RW_A].size = get_size_from_header(as_header(image, rw_offset));
1376*4f2df630SAndroid Build Coastguard Worker
1377*4f2df630SAndroid Build Coastguard Worker /* Validate the RO_B header */
1378*4f2df630SAndroid Build Coastguard Worker if (!valid_image_header(as_header(image, slot_a_end),
1379*4f2df630SAndroid Build Coastguard Worker image->data_len - slot_a_end, NULL)) {
1380*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: RO_B header is invalid\n");
1381*4f2df630SAndroid Build Coastguard Worker return false;
1382*4f2df630SAndroid Build Coastguard Worker }
1383*4f2df630SAndroid Build Coastguard Worker sections[RO_B].offset = slot_a_end;
1384*4f2df630SAndroid Build Coastguard Worker sections[RO_B].size =
1385*4f2df630SAndroid Build Coastguard Worker get_size_from_header(as_header(image, slot_a_end));
1386*4f2df630SAndroid Build Coastguard Worker
1387*4f2df630SAndroid Build Coastguard Worker /* Find RW_B */
1388*4f2df630SAndroid Build Coastguard Worker rw_offset = find_rw_header(image,
1389*4f2df630SAndroid Build Coastguard Worker sections[RO_B].offset + sections[RO_B].size,
1390*4f2df630SAndroid Build Coastguard Worker image->data_len);
1391*4f2df630SAndroid Build Coastguard Worker if (rw_offset == -1) {
1392*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: RW_B header cannot be found\n");
1393*4f2df630SAndroid Build Coastguard Worker return false;
1394*4f2df630SAndroid Build Coastguard Worker }
1395*4f2df630SAndroid Build Coastguard Worker sections[RW_B].offset = rw_offset;
1396*4f2df630SAndroid Build Coastguard Worker sections[RW_B].size = get_size_from_header(as_header(image, rw_offset));
1397*4f2df630SAndroid Build Coastguard Worker
1398*4f2df630SAndroid Build Coastguard Worker /* We found all of the headers and updated offset/size in sections */
1399*4f2df630SAndroid Build Coastguard Worker return true;
1400*4f2df630SAndroid Build Coastguard Worker }
1401*4f2df630SAndroid Build Coastguard Worker
1402*4f2df630SAndroid Build Coastguard Worker /*
1403*4f2df630SAndroid Build Coastguard Worker * Scan the new image and retrieve versions of all four sections, two RO and
1404*4f2df630SAndroid Build Coastguard Worker * two RW, verifying that image size is not too short along the way.
1405*4f2df630SAndroid Build Coastguard Worker */
fetch_header_versions(struct image * image)1406*4f2df630SAndroid Build Coastguard Worker static bool fetch_header_versions(struct image *image)
1407*4f2df630SAndroid Build Coastguard Worker {
1408*4f2df630SAndroid Build Coastguard Worker size_t i;
1409*4f2df630SAndroid Build Coastguard Worker struct section_t *const sections = image->sections;
1410*4f2df630SAndroid Build Coastguard Worker
1411*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < NUM_SECTIONS; i++) {
1412*4f2df630SAndroid Build Coastguard Worker const struct typed_image_header h =
1413*4f2df630SAndroid Build Coastguard Worker as_header(image, sections[i].offset);
1414*4f2df630SAndroid Build Coastguard Worker
1415*4f2df630SAndroid Build Coastguard Worker if (get_size_from_header(h) < CONFIG_FLASH_BANK_SIZE) {
1416*4f2df630SAndroid Build Coastguard Worker /*
1417*4f2df630SAndroid Build Coastguard Worker * Return an error for incorrectly signed images. If
1418*4f2df630SAndroid Build Coastguard Worker * it's a RO image with 0 as its size, ignore the error.
1419*4f2df630SAndroid Build Coastguard Worker *
1420*4f2df630SAndroid Build Coastguard Worker * TODO(b/273510573): revisit after dbg versioning is
1421*4f2df630SAndroid Build Coastguard Worker * figured out.
1422*4f2df630SAndroid Build Coastguard Worker */
1423*4f2df630SAndroid Build Coastguard Worker if (get_size_from_header(h) || sections[i].offset) {
1424*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
1425*4f2df630SAndroid Build Coastguard Worker "Image at offset %#5x too short "
1426*4f2df630SAndroid Build Coastguard Worker "(%d bytes)\n",
1427*4f2df630SAndroid Build Coastguard Worker sections[i].offset, h.h->image_size);
1428*4f2df630SAndroid Build Coastguard Worker return false;
1429*4f2df630SAndroid Build Coastguard Worker }
1430*4f2df630SAndroid Build Coastguard Worker
1431*4f2df630SAndroid Build Coastguard Worker printf("warning: invalid RO_A (size 0)\n");
1432*4f2df630SAndroid Build Coastguard Worker }
1433*4f2df630SAndroid Build Coastguard Worker if (h.type == GSC_DEVICE_H1 || h.type == GSC_DEVICE_DT) {
1434*4f2df630SAndroid Build Coastguard Worker sections[i].shv.epoch = h.h->epoch_;
1435*4f2df630SAndroid Build Coastguard Worker sections[i].shv.major = h.h->major_;
1436*4f2df630SAndroid Build Coastguard Worker sections[i].shv.minor = h.h->minor_;
1437*4f2df630SAndroid Build Coastguard Worker sections[i].keyid = h.h->keyid;
1438*4f2df630SAndroid Build Coastguard Worker } else if (h.type == GSC_DEVICE_NT) {
1439*4f2df630SAndroid Build Coastguard Worker sections[i].shv.epoch = h.m->security_version;
1440*4f2df630SAndroid Build Coastguard Worker sections[i].shv.major = h.m->version_major;
1441*4f2df630SAndroid Build Coastguard Worker sections[i].shv.minor = h.m->version_minor;
1442*4f2df630SAndroid Build Coastguard Worker sections[i].keyid = 0;
1443*4f2df630SAndroid Build Coastguard Worker } else {
1444*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: Unknown image type.\n");
1445*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1446*4f2df630SAndroid Build Coastguard Worker }
1447*4f2df630SAndroid Build Coastguard Worker }
1448*4f2df630SAndroid Build Coastguard Worker return true;
1449*4f2df630SAndroid Build Coastguard Worker }
1450*4f2df630SAndroid Build Coastguard Worker
1451*4f2df630SAndroid Build Coastguard Worker /* Compare to signer headers and determine which one is newer. */
a_newer_than_b(const struct signed_header_version * a,const struct signed_header_version * b)1452*4f2df630SAndroid Build Coastguard Worker static int a_newer_than_b(const struct signed_header_version *a,
1453*4f2df630SAndroid Build Coastguard Worker const struct signed_header_version *b)
1454*4f2df630SAndroid Build Coastguard Worker {
1455*4f2df630SAndroid Build Coastguard Worker uint32_t fields[][3] = {
1456*4f2df630SAndroid Build Coastguard Worker { a->epoch, a->major, a->minor },
1457*4f2df630SAndroid Build Coastguard Worker { b->epoch, b->major, b->minor },
1458*4f2df630SAndroid Build Coastguard Worker };
1459*4f2df630SAndroid Build Coastguard Worker size_t i;
1460*4f2df630SAndroid Build Coastguard Worker
1461*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(fields[0]); i++) {
1462*4f2df630SAndroid Build Coastguard Worker uint32_t a_value;
1463*4f2df630SAndroid Build Coastguard Worker uint32_t b_value;
1464*4f2df630SAndroid Build Coastguard Worker
1465*4f2df630SAndroid Build Coastguard Worker a_value = fields[0][i];
1466*4f2df630SAndroid Build Coastguard Worker b_value = fields[1][i];
1467*4f2df630SAndroid Build Coastguard Worker
1468*4f2df630SAndroid Build Coastguard Worker /*
1469*4f2df630SAndroid Build Coastguard Worker * Let's filter out images where the section is not
1470*4f2df630SAndroid Build Coastguard Worker * initialized and the version field value is set to all ones.
1471*4f2df630SAndroid Build Coastguard Worker */
1472*4f2df630SAndroid Build Coastguard Worker if (a_value == 0xffffffff)
1473*4f2df630SAndroid Build Coastguard Worker a_value = 0;
1474*4f2df630SAndroid Build Coastguard Worker
1475*4f2df630SAndroid Build Coastguard Worker if (b_value == 0xffffffff)
1476*4f2df630SAndroid Build Coastguard Worker b_value = 0;
1477*4f2df630SAndroid Build Coastguard Worker
1478*4f2df630SAndroid Build Coastguard Worker if (a_value != b_value)
1479*4f2df630SAndroid Build Coastguard Worker return a_value > b_value;
1480*4f2df630SAndroid Build Coastguard Worker }
1481*4f2df630SAndroid Build Coastguard Worker
1482*4f2df630SAndroid Build Coastguard Worker return 0; /* All else being equal A is no newer than B. */
1483*4f2df630SAndroid Build Coastguard Worker }
1484*4f2df630SAndroid Build Coastguard Worker
1485*4f2df630SAndroid Build Coastguard Worker /*
1486*4f2df630SAndroid Build Coastguard Worker * Pick sections to transfer based on information retrieved from the target,
1487*4f2df630SAndroid Build Coastguard Worker * the new image, and the protocol version the target is running.
1488*4f2df630SAndroid Build Coastguard Worker */
pick_sections(struct transfer_descriptor * td,struct image * image)1489*4f2df630SAndroid Build Coastguard Worker static void pick_sections(struct transfer_descriptor *td, struct image *image)
1490*4f2df630SAndroid Build Coastguard Worker {
1491*4f2df630SAndroid Build Coastguard Worker size_t i;
1492*4f2df630SAndroid Build Coastguard Worker struct section_t *sections = image->sections;
1493*4f2df630SAndroid Build Coastguard Worker
1494*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < NUM_SECTIONS; i++) {
1495*4f2df630SAndroid Build Coastguard Worker uint32_t offset = sections[i].offset;
1496*4f2df630SAndroid Build Coastguard Worker
1497*4f2df630SAndroid Build Coastguard Worker if ((i == RW_A) || (i == RW_B)) {
1498*4f2df630SAndroid Build Coastguard Worker /* Skip currently active RW section. */
1499*4f2df630SAndroid Build Coastguard Worker bool active_rw_slot_b = td->rw_offset <
1500*4f2df630SAndroid Build Coastguard Worker sections[RO_B].offset;
1501*4f2df630SAndroid Build Coastguard Worker if ((i == RW_B) == active_rw_slot_b)
1502*4f2df630SAndroid Build Coastguard Worker continue;
1503*4f2df630SAndroid Build Coastguard Worker /*
1504*4f2df630SAndroid Build Coastguard Worker * Ok, this would be the RW section to transfer to the
1505*4f2df630SAndroid Build Coastguard Worker * device. Is it newer in the new image than the
1506*4f2df630SAndroid Build Coastguard Worker * running RW section on the device?
1507*4f2df630SAndroid Build Coastguard Worker *
1508*4f2df630SAndroid Build Coastguard Worker * If not in 'upstart' mode - transfer even if
1509*4f2df630SAndroid Build Coastguard Worker * versions are the same, timestamps could be
1510*4f2df630SAndroid Build Coastguard Worker * different.
1511*4f2df630SAndroid Build Coastguard Worker */
1512*4f2df630SAndroid Build Coastguard Worker
1513*4f2df630SAndroid Build Coastguard Worker if (a_newer_than_b(§ions[i].shv, &targ.shv[1]) ||
1514*4f2df630SAndroid Build Coastguard Worker !td->upstart_mode) {
1515*4f2df630SAndroid Build Coastguard Worker sections[i].update_needed = true;
1516*4f2df630SAndroid Build Coastguard Worker }
1517*4f2df630SAndroid Build Coastguard Worker /* Rest of loop is RO */
1518*4f2df630SAndroid Build Coastguard Worker continue;
1519*4f2df630SAndroid Build Coastguard Worker }
1520*4f2df630SAndroid Build Coastguard Worker
1521*4f2df630SAndroid Build Coastguard Worker /* Skip currently active RO section. */
1522*4f2df630SAndroid Build Coastguard Worker if (offset != td->ro_offset)
1523*4f2df630SAndroid Build Coastguard Worker continue;
1524*4f2df630SAndroid Build Coastguard Worker /*
1525*4f2df630SAndroid Build Coastguard Worker * Ok, this would be the RO section to transfer to the device.
1526*4f2df630SAndroid Build Coastguard Worker * Is it newer in the new image than the running RO section on
1527*4f2df630SAndroid Build Coastguard Worker * the device?
1528*4f2df630SAndroid Build Coastguard Worker */
1529*4f2df630SAndroid Build Coastguard Worker if (a_newer_than_b(§ions[i].shv, &targ.shv[0]) ||
1530*4f2df630SAndroid Build Coastguard Worker td->force_ro)
1531*4f2df630SAndroid Build Coastguard Worker sections[i].update_needed = true;
1532*4f2df630SAndroid Build Coastguard Worker }
1533*4f2df630SAndroid Build Coastguard Worker }
1534*4f2df630SAndroid Build Coastguard Worker
1535*4f2df630SAndroid Build Coastguard Worker /*
1536*4f2df630SAndroid Build Coastguard Worker * Indicate to the target that update image transfer has been completed. Upon
1537*4f2df630SAndroid Build Coastguard Worker * receiving of this message the target state machine transitions into the
1538*4f2df630SAndroid Build Coastguard Worker * 'rx_idle' state. The host may send an extension command to reset the target
1539*4f2df630SAndroid Build Coastguard Worker * after this.
1540*4f2df630SAndroid Build Coastguard Worker */
send_done(struct usb_endpoint * uep)1541*4f2df630SAndroid Build Coastguard Worker static void send_done(struct usb_endpoint *uep)
1542*4f2df630SAndroid Build Coastguard Worker {
1543*4f2df630SAndroid Build Coastguard Worker uint32_t out;
1544*4f2df630SAndroid Build Coastguard Worker
1545*4f2df630SAndroid Build Coastguard Worker /* Send stop request, ignoring reply. */
1546*4f2df630SAndroid Build Coastguard Worker out = htobe32(UPGRADE_DONE);
1547*4f2df630SAndroid Build Coastguard Worker do_xfer(uep, &out, sizeof(out), &out, 1, 0, NULL);
1548*4f2df630SAndroid Build Coastguard Worker }
1549*4f2df630SAndroid Build Coastguard Worker
1550*4f2df630SAndroid Build Coastguard Worker /*
1551*4f2df630SAndroid Build Coastguard Worker * Gets and caches the GSC version information from the currently connected
1552*4f2df630SAndroid Build Coastguard Worker * device.
1553*4f2df630SAndroid Build Coastguard Worker */
get_version(struct transfer_descriptor * td,bool leave_pending)1554*4f2df630SAndroid Build Coastguard Worker static void get_version(struct transfer_descriptor *td, bool leave_pending)
1555*4f2df630SAndroid Build Coastguard Worker {
1556*4f2df630SAndroid Build Coastguard Worker size_t rxed_size;
1557*4f2df630SAndroid Build Coastguard Worker size_t i;
1558*4f2df630SAndroid Build Coastguard Worker uint32_t error_code;
1559*4f2df630SAndroid Build Coastguard Worker
1560*4f2df630SAndroid Build Coastguard Worker /*
1561*4f2df630SAndroid Build Coastguard Worker * Need to be backwards compatible, communicate with targets running
1562*4f2df630SAndroid Build Coastguard Worker * different protocol versions.
1563*4f2df630SAndroid Build Coastguard Worker */
1564*4f2df630SAndroid Build Coastguard Worker union {
1565*4f2df630SAndroid Build Coastguard Worker struct first_response_pdu rpdu;
1566*4f2df630SAndroid Build Coastguard Worker uint32_t legacy_resp;
1567*4f2df630SAndroid Build Coastguard Worker } start_resp;
1568*4f2df630SAndroid Build Coastguard Worker
1569*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer) {
1570*4f2df630SAndroid Build Coastguard Worker struct update_pdu updu;
1571*4f2df630SAndroid Build Coastguard Worker
1572*4f2df630SAndroid Build Coastguard Worker memset(&updu, 0, sizeof(updu));
1573*4f2df630SAndroid Build Coastguard Worker updu.block_size = htobe32(sizeof(updu));
1574*4f2df630SAndroid Build Coastguard Worker do_xfer(&td->uep, &updu, sizeof(updu), &start_resp,
1575*4f2df630SAndroid Build Coastguard Worker sizeof(start_resp), 1, &rxed_size);
1576*4f2df630SAndroid Build Coastguard Worker } else {
1577*4f2df630SAndroid Build Coastguard Worker rxed_size = sizeof(start_resp);
1578*4f2df630SAndroid Build Coastguard Worker if (tpm_send_pkt(td, 0, 0, NULL, 0, &start_resp, &rxed_size,
1579*4f2df630SAndroid Build Coastguard Worker EXTENSION_FW_UPGRADE) < 0) {
1580*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Failed to start transfer\n");
1581*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1582*4f2df630SAndroid Build Coastguard Worker }
1583*4f2df630SAndroid Build Coastguard Worker }
1584*4f2df630SAndroid Build Coastguard Worker
1585*4f2df630SAndroid Build Coastguard Worker /* We got something. Check for errors in response */
1586*4f2df630SAndroid Build Coastguard Worker if (rxed_size < 8) {
1587*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected response size %zd: ", rxed_size);
1588*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < rxed_size; i++)
1589*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, " %02x", ((uint8_t *)&start_resp)[i]);
1590*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\n");
1591*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1592*4f2df630SAndroid Build Coastguard Worker }
1593*4f2df630SAndroid Build Coastguard Worker
1594*4f2df630SAndroid Build Coastguard Worker protocol_version = be32toh(start_resp.rpdu.protocol_version);
1595*4f2df630SAndroid Build Coastguard Worker if (protocol_version < 5) {
1596*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unsupported protocol version %d\n",
1597*4f2df630SAndroid Build Coastguard Worker protocol_version);
1598*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1599*4f2df630SAndroid Build Coastguard Worker }
1600*4f2df630SAndroid Build Coastguard Worker
1601*4f2df630SAndroid Build Coastguard Worker error_code = be32toh(start_resp.rpdu.return_value);
1602*4f2df630SAndroid Build Coastguard Worker
1603*4f2df630SAndroid Build Coastguard Worker if (error_code) {
1604*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Target reporting error %d\n", error_code);
1605*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer)
1606*4f2df630SAndroid Build Coastguard Worker shut_down(&td->uep);
1607*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1608*4f2df630SAndroid Build Coastguard Worker }
1609*4f2df630SAndroid Build Coastguard Worker
1610*4f2df630SAndroid Build Coastguard Worker td->rw_offset = be32toh(start_resp.rpdu.backup_rw_offset);
1611*4f2df630SAndroid Build Coastguard Worker td->ro_offset = be32toh(start_resp.rpdu.backup_ro_offset);
1612*4f2df630SAndroid Build Coastguard Worker
1613*4f2df630SAndroid Build Coastguard Worker /* Running header versions. */
1614*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(targ.shv); i++) {
1615*4f2df630SAndroid Build Coastguard Worker targ.shv[i].minor = be32toh(start_resp.rpdu.shv[i].minor);
1616*4f2df630SAndroid Build Coastguard Worker targ.shv[i].major = be32toh(start_resp.rpdu.shv[i].major);
1617*4f2df630SAndroid Build Coastguard Worker targ.shv[i].epoch = be32toh(start_resp.rpdu.shv[i].epoch);
1618*4f2df630SAndroid Build Coastguard Worker }
1619*4f2df630SAndroid Build Coastguard Worker
1620*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(targ.keyid); i++)
1621*4f2df630SAndroid Build Coastguard Worker targ.keyid[i] = be32toh(start_resp.rpdu.keyid[i]);
1622*4f2df630SAndroid Build Coastguard Worker
1623*4f2df630SAndroid Build Coastguard Worker if (!leave_pending && td->ep_type == usb_xfer)
1624*4f2df630SAndroid Build Coastguard Worker send_done(&td->uep);
1625*4f2df630SAndroid Build Coastguard Worker }
1626*4f2df630SAndroid Build Coastguard Worker
setup_connection(struct transfer_descriptor * td)1627*4f2df630SAndroid Build Coastguard Worker static void setup_connection(struct transfer_descriptor *td)
1628*4f2df630SAndroid Build Coastguard Worker {
1629*4f2df630SAndroid Build Coastguard Worker /* Send start request. */
1630*4f2df630SAndroid Build Coastguard Worker printf("start\n");
1631*4f2df630SAndroid Build Coastguard Worker
1632*4f2df630SAndroid Build Coastguard Worker get_version(td, true);
1633*4f2df630SAndroid Build Coastguard Worker
1634*4f2df630SAndroid Build Coastguard Worker printf("keyids: RO 0x%08x, RW 0x%08x\n", targ.keyid[0], targ.keyid[1]);
1635*4f2df630SAndroid Build Coastguard Worker printf("offsets: backup RO at %#x, backup RW at %#x\n", td->ro_offset,
1636*4f2df630SAndroid Build Coastguard Worker td->rw_offset);
1637*4f2df630SAndroid Build Coastguard Worker }
1638*4f2df630SAndroid Build Coastguard Worker
1639*4f2df630SAndroid Build Coastguard Worker /*
1640*4f2df630SAndroid Build Coastguard Worker * Channel TPM extension/vendor command over USB. The payload of the USB frame
1641*4f2df630SAndroid Build Coastguard Worker * in this case consists of the 2 byte subcommand code concatenated with the
1642*4f2df630SAndroid Build Coastguard Worker * command body. The caller needs to indicate if a response is expected, and
1643*4f2df630SAndroid Build Coastguard Worker * if it is - of what maximum size.
1644*4f2df630SAndroid Build Coastguard Worker */
ext_cmd_over_usb(struct usb_endpoint * uep,uint16_t subcommand,const void * cmd_body,size_t body_size,void * resp,size_t * resp_size)1645*4f2df630SAndroid Build Coastguard Worker static int ext_cmd_over_usb(struct usb_endpoint *uep, uint16_t subcommand,
1646*4f2df630SAndroid Build Coastguard Worker const void *cmd_body, size_t body_size, void *resp,
1647*4f2df630SAndroid Build Coastguard Worker size_t *resp_size)
1648*4f2df630SAndroid Build Coastguard Worker {
1649*4f2df630SAndroid Build Coastguard Worker struct update_frame_header *ufh;
1650*4f2df630SAndroid Build Coastguard Worker uint16_t *frame_ptr;
1651*4f2df630SAndroid Build Coastguard Worker size_t usb_msg_size;
1652*4f2df630SAndroid Build Coastguard Worker EVP_MD_CTX *ctx;
1653*4f2df630SAndroid Build Coastguard Worker
1654*4f2df630SAndroid Build Coastguard Worker usb_msg_size = sizeof(struct update_frame_header) + sizeof(subcommand) +
1655*4f2df630SAndroid Build Coastguard Worker body_size;
1656*4f2df630SAndroid Build Coastguard Worker
1657*4f2df630SAndroid Build Coastguard Worker ufh = malloc(usb_msg_size);
1658*4f2df630SAndroid Build Coastguard Worker if (!ufh) {
1659*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "%s: failed to allocate %zd bytes\n", __func__,
1660*4f2df630SAndroid Build Coastguard Worker usb_msg_size);
1661*4f2df630SAndroid Build Coastguard Worker return -1;
1662*4f2df630SAndroid Build Coastguard Worker }
1663*4f2df630SAndroid Build Coastguard Worker
1664*4f2df630SAndroid Build Coastguard Worker ufh->block_size = htobe32(usb_msg_size);
1665*4f2df630SAndroid Build Coastguard Worker ufh->cmd.block_base = htobe32(CONFIG_EXTENSION_COMMAND);
1666*4f2df630SAndroid Build Coastguard Worker frame_ptr = (uint16_t *)(ufh + 1);
1667*4f2df630SAndroid Build Coastguard Worker *frame_ptr = htobe16(subcommand);
1668*4f2df630SAndroid Build Coastguard Worker
1669*4f2df630SAndroid Build Coastguard Worker if (body_size)
1670*4f2df630SAndroid Build Coastguard Worker memcpy(frame_ptr + 1, cmd_body, body_size);
1671*4f2df630SAndroid Build Coastguard Worker
1672*4f2df630SAndroid Build Coastguard Worker /* Calculate the digest. */
1673*4f2df630SAndroid Build Coastguard Worker ctx = EVP_MD_CTX_new();
1674*4f2df630SAndroid Build Coastguard Worker sha_init(ctx);
1675*4f2df630SAndroid Build Coastguard Worker sha_update(ctx, &ufh->cmd.block_base,
1676*4f2df630SAndroid Build Coastguard Worker usb_msg_size - offsetof(struct update_frame_header,
1677*4f2df630SAndroid Build Coastguard Worker cmd.block_base));
1678*4f2df630SAndroid Build Coastguard Worker sha_final_into_block_digest(ctx, &ufh->cmd.block_digest,
1679*4f2df630SAndroid Build Coastguard Worker sizeof(ufh->cmd.block_digest));
1680*4f2df630SAndroid Build Coastguard Worker EVP_MD_CTX_free(ctx);
1681*4f2df630SAndroid Build Coastguard Worker
1682*4f2df630SAndroid Build Coastguard Worker do_xfer(uep, ufh, usb_msg_size, resp, resp_size ? *resp_size : 0, 1,
1683*4f2df630SAndroid Build Coastguard Worker resp_size);
1684*4f2df630SAndroid Build Coastguard Worker
1685*4f2df630SAndroid Build Coastguard Worker free(ufh);
1686*4f2df630SAndroid Build Coastguard Worker return 0;
1687*4f2df630SAndroid Build Coastguard Worker }
1688*4f2df630SAndroid Build Coastguard Worker
1689*4f2df630SAndroid Build Coastguard Worker /*
1690*4f2df630SAndroid Build Coastguard Worker * Old cr50 images fail the update if sections are sent out of order. They
1691*4f2df630SAndroid Build Coastguard Worker * require each block to have an offset greater than the block that was sent
1692*4f2df630SAndroid Build Coastguard Worker * before. RO has a lower offset than RW, so old cr50 images reject RO if it's
1693*4f2df630SAndroid Build Coastguard Worker * sent right after RW.
1694*4f2df630SAndroid Build Coastguard Worker * This offset restriction expires after 60 seconds. Delay the RO update long
1695*4f2df630SAndroid Build Coastguard Worker * enough for cr50 to not care that it has a lower offset than RW.
1696*4f2df630SAndroid Build Coastguard Worker *
1697*4f2df630SAndroid Build Coastguard Worker * Make the delay 65 seconds instead of 60 to cover differences in the speed of
1698*4f2df630SAndroid Build Coastguard Worker * H1's clock and the host clock.
1699*4f2df630SAndroid Build Coastguard Worker */
1700*4f2df630SAndroid Build Coastguard Worker #define NEXT_SECTION_DELAY 65
1701*4f2df630SAndroid Build Coastguard Worker
1702*4f2df630SAndroid Build Coastguard Worker /*
1703*4f2df630SAndroid Build Coastguard Worker * H1 support for flashing RO immediately after RW added in 0.3.20/0.4.20.
1704*4f2df630SAndroid Build Coastguard Worker * D2 support exists in all versions.
1705*4f2df630SAndroid Build Coastguard Worker * NT support exists in all versions.
1706*4f2df630SAndroid Build Coastguard Worker */
supports_reordered_section_updates(struct signed_header_version * rw)1707*4f2df630SAndroid Build Coastguard Worker static int supports_reordered_section_updates(struct signed_header_version *rw)
1708*4f2df630SAndroid Build Coastguard Worker {
1709*4f2df630SAndroid Build Coastguard Worker switch (gsc_dev) {
1710*4f2df630SAndroid Build Coastguard Worker case GSC_DEVICE_H1:
1711*4f2df630SAndroid Build Coastguard Worker return (rw->epoch || rw->major > 4 ||
1712*4f2df630SAndroid Build Coastguard Worker (rw->major >= 3 && rw->minor >= 20));
1713*4f2df630SAndroid Build Coastguard Worker case GSC_DEVICE_DT:
1714*4f2df630SAndroid Build Coastguard Worker return true;
1715*4f2df630SAndroid Build Coastguard Worker case GSC_DEVICE_NT:
1716*4f2df630SAndroid Build Coastguard Worker return true;
1717*4f2df630SAndroid Build Coastguard Worker default:
1718*4f2df630SAndroid Build Coastguard Worker return false;
1719*4f2df630SAndroid Build Coastguard Worker }
1720*4f2df630SAndroid Build Coastguard Worker }
1721*4f2df630SAndroid Build Coastguard Worker
1722*4f2df630SAndroid Build Coastguard Worker /* Returns number of successfully transmitted image sections. */
transfer_image(struct transfer_descriptor * td,struct image * image)1723*4f2df630SAndroid Build Coastguard Worker static int transfer_image(struct transfer_descriptor *td, struct image *image)
1724*4f2df630SAndroid Build Coastguard Worker {
1725*4f2df630SAndroid Build Coastguard Worker size_t i;
1726*4f2df630SAndroid Build Coastguard Worker int num_txed_sections = 0;
1727*4f2df630SAndroid Build Coastguard Worker int needs_delay = !supports_reordered_section_updates(&targ.shv[1]);
1728*4f2df630SAndroid Build Coastguard Worker struct section_t *sections = image->sections;
1729*4f2df630SAndroid Build Coastguard Worker
1730*4f2df630SAndroid Build Coastguard Worker /*
1731*4f2df630SAndroid Build Coastguard Worker * In case both RO and RW updates are required, make sure the RW
1732*4f2df630SAndroid Build Coastguard Worker * section is updated before the RO. The array below keeps sections
1733*4f2df630SAndroid Build Coastguard Worker * offsets in the required order.
1734*4f2df630SAndroid Build Coastguard Worker */
1735*4f2df630SAndroid Build Coastguard Worker const enum section update_order[] = { RW_A, RW_B, RO_A, RO_B };
1736*4f2df630SAndroid Build Coastguard Worker
1737*4f2df630SAndroid Build Coastguard Worker /* Now that we have an active connection and an image, pick sections */
1738*4f2df630SAndroid Build Coastguard Worker pick_sections(td, image);
1739*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(update_order); i++) {
1740*4f2df630SAndroid Build Coastguard Worker const enum section sect = update_order[i];
1741*4f2df630SAndroid Build Coastguard Worker
1742*4f2df630SAndroid Build Coastguard Worker if (!sections[sect].update_needed)
1743*4f2df630SAndroid Build Coastguard Worker continue;
1744*4f2df630SAndroid Build Coastguard Worker if (num_txed_sections && needs_delay) {
1745*4f2df630SAndroid Build Coastguard Worker /*
1746*4f2df630SAndroid Build Coastguard Worker * Delays more than 5 seconds cause the update
1747*4f2df630SAndroid Build Coastguard Worker * to timeout. End the update before the delay
1748*4f2df630SAndroid Build Coastguard Worker * and set it up after to recover from the
1749*4f2df630SAndroid Build Coastguard Worker * timeout.
1750*4f2df630SAndroid Build Coastguard Worker */
1751*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer)
1752*4f2df630SAndroid Build Coastguard Worker send_done(&td->uep);
1753*4f2df630SAndroid Build Coastguard Worker printf("Waiting %ds for %s update.\n",
1754*4f2df630SAndroid Build Coastguard Worker NEXT_SECTION_DELAY, SECTION_NAMES[sect]);
1755*4f2df630SAndroid Build Coastguard Worker sleep(NEXT_SECTION_DELAY);
1756*4f2df630SAndroid Build Coastguard Worker setup_connection(td);
1757*4f2df630SAndroid Build Coastguard Worker /* Pick sections again in case GSC versions changed. */
1758*4f2df630SAndroid Build Coastguard Worker pick_sections(td, image);
1759*4f2df630SAndroid Build Coastguard Worker }
1760*4f2df630SAndroid Build Coastguard Worker
1761*4f2df630SAndroid Build Coastguard Worker transfer_section(td, image->data + sections[sect].offset,
1762*4f2df630SAndroid Build Coastguard Worker sections[sect].offset, sections[sect].size);
1763*4f2df630SAndroid Build Coastguard Worker num_txed_sections++;
1764*4f2df630SAndroid Build Coastguard Worker }
1765*4f2df630SAndroid Build Coastguard Worker
1766*4f2df630SAndroid Build Coastguard Worker if (!num_txed_sections)
1767*4f2df630SAndroid Build Coastguard Worker printf("nothing to do\n");
1768*4f2df630SAndroid Build Coastguard Worker else
1769*4f2df630SAndroid Build Coastguard Worker printf("-------\nupdate complete\n");
1770*4f2df630SAndroid Build Coastguard Worker return num_txed_sections;
1771*4f2df630SAndroid Build Coastguard Worker }
1772*4f2df630SAndroid Build Coastguard Worker
send_vendor_command(struct transfer_descriptor * td,uint16_t subcommand,const void * command_body,size_t command_body_size,void * response,size_t * response_size)1773*4f2df630SAndroid Build Coastguard Worker uint32_t send_vendor_command(struct transfer_descriptor *td,
1774*4f2df630SAndroid Build Coastguard Worker uint16_t subcommand, const void *command_body,
1775*4f2df630SAndroid Build Coastguard Worker size_t command_body_size, void *response,
1776*4f2df630SAndroid Build Coastguard Worker size_t *response_size)
1777*4f2df630SAndroid Build Coastguard Worker {
1778*4f2df630SAndroid Build Coastguard Worker int32_t rv;
1779*4f2df630SAndroid Build Coastguard Worker
1780*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer) {
1781*4f2df630SAndroid Build Coastguard Worker /*
1782*4f2df630SAndroid Build Coastguard Worker * When communicating over USB the response is always supposed
1783*4f2df630SAndroid Build Coastguard Worker * to have the result code in the first byte of the response,
1784*4f2df630SAndroid Build Coastguard Worker * to be stripped from the actual response body by this
1785*4f2df630SAndroid Build Coastguard Worker * function.
1786*4f2df630SAndroid Build Coastguard Worker */
1787*4f2df630SAndroid Build Coastguard Worker uint8_t temp_response[MAX_RX_BUF_SIZE];
1788*4f2df630SAndroid Build Coastguard Worker size_t max_response_size;
1789*4f2df630SAndroid Build Coastguard Worker
1790*4f2df630SAndroid Build Coastguard Worker if (!response_size) {
1791*4f2df630SAndroid Build Coastguard Worker max_response_size = 1;
1792*4f2df630SAndroid Build Coastguard Worker } else if (*response_size < (sizeof(temp_response))) {
1793*4f2df630SAndroid Build Coastguard Worker max_response_size = *response_size + 1;
1794*4f2df630SAndroid Build Coastguard Worker } else {
1795*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
1796*4f2df630SAndroid Build Coastguard Worker "Error: Expected response too large (%zd)\n",
1797*4f2df630SAndroid Build Coastguard Worker *response_size);
1798*4f2df630SAndroid Build Coastguard Worker /* Should happen only when debugging. */
1799*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1800*4f2df630SAndroid Build Coastguard Worker }
1801*4f2df630SAndroid Build Coastguard Worker
1802*4f2df630SAndroid Build Coastguard Worker ext_cmd_over_usb(&td->uep, subcommand, command_body,
1803*4f2df630SAndroid Build Coastguard Worker command_body_size, temp_response,
1804*4f2df630SAndroid Build Coastguard Worker &max_response_size);
1805*4f2df630SAndroid Build Coastguard Worker if (!max_response_size) {
1806*4f2df630SAndroid Build Coastguard Worker /*
1807*4f2df630SAndroid Build Coastguard Worker * we must be talking to an older Cr50 firmware, which
1808*4f2df630SAndroid Build Coastguard Worker * does not return the result code in the first byte
1809*4f2df630SAndroid Build Coastguard Worker * on success, nothing to do.
1810*4f2df630SAndroid Build Coastguard Worker */
1811*4f2df630SAndroid Build Coastguard Worker if (response_size)
1812*4f2df630SAndroid Build Coastguard Worker *response_size = 0;
1813*4f2df630SAndroid Build Coastguard Worker rv = 0;
1814*4f2df630SAndroid Build Coastguard Worker } else {
1815*4f2df630SAndroid Build Coastguard Worker rv = temp_response[0];
1816*4f2df630SAndroid Build Coastguard Worker if (response_size) {
1817*4f2df630SAndroid Build Coastguard Worker *response_size = max_response_size - 1;
1818*4f2df630SAndroid Build Coastguard Worker memcpy(response, temp_response + 1,
1819*4f2df630SAndroid Build Coastguard Worker *response_size);
1820*4f2df630SAndroid Build Coastguard Worker }
1821*4f2df630SAndroid Build Coastguard Worker }
1822*4f2df630SAndroid Build Coastguard Worker } else {
1823*4f2df630SAndroid Build Coastguard Worker rv = tpm_send_pkt(td, 0, 0, command_body, command_body_size,
1824*4f2df630SAndroid Build Coastguard Worker response, response_size, subcommand);
1825*4f2df630SAndroid Build Coastguard Worker
1826*4f2df630SAndroid Build Coastguard Worker if (rv == -1) {
1827*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
1828*4f2df630SAndroid Build Coastguard Worker "Error: Failed to send vendor command %d\n",
1829*4f2df630SAndroid Build Coastguard Worker subcommand);
1830*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1831*4f2df630SAndroid Build Coastguard Worker }
1832*4f2df630SAndroid Build Coastguard Worker }
1833*4f2df630SAndroid Build Coastguard Worker
1834*4f2df630SAndroid Build Coastguard Worker return rv; /* This will be converted into uint32_t */
1835*4f2df630SAndroid Build Coastguard Worker }
1836*4f2df630SAndroid Build Coastguard Worker
1837*4f2df630SAndroid Build Coastguard Worker /*
1838*4f2df630SAndroid Build Coastguard Worker * Corrupt the header of the inactive rw image to make sure the system can't
1839*4f2df630SAndroid Build Coastguard Worker * rollback
1840*4f2df630SAndroid Build Coastguard Worker */
invalidate_inactive_rw(struct transfer_descriptor * td)1841*4f2df630SAndroid Build Coastguard Worker static void invalidate_inactive_rw(struct transfer_descriptor *td)
1842*4f2df630SAndroid Build Coastguard Worker {
1843*4f2df630SAndroid Build Coastguard Worker /* Corrupt the rw image that is not running. */
1844*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
1845*4f2df630SAndroid Build Coastguard Worker
1846*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_INVALIDATE_INACTIVE_RW, NULL, 0,
1847*4f2df630SAndroid Build Coastguard Worker NULL, NULL);
1848*4f2df630SAndroid Build Coastguard Worker if (!rv) {
1849*4f2df630SAndroid Build Coastguard Worker printf("Inactive header invalidated\n");
1850*4f2df630SAndroid Build Coastguard Worker return;
1851*4f2df630SAndroid Build Coastguard Worker }
1852*4f2df630SAndroid Build Coastguard Worker
1853*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "*%s: Error %#x\n", __func__, rv);
1854*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1855*4f2df630SAndroid Build Coastguard Worker }
1856*4f2df630SAndroid Build Coastguard Worker
1857*4f2df630SAndroid Build Coastguard Worker /*
1858*4f2df630SAndroid Build Coastguard Worker * Try setting CCD capability.
1859*4f2df630SAndroid Build Coastguard Worker *
1860*4f2df630SAndroid Build Coastguard Worker * The 'parameter' string includes capability and desired new state separated
1861*4f2df630SAndroid Build Coastguard Worker * by a ':', both parts could be abbreviated and checked for the match as case
1862*4f2df630SAndroid Build Coastguard Worker * insensitive.
1863*4f2df630SAndroid Build Coastguard Worker *
1864*4f2df630SAndroid Build Coastguard Worker * The result of the attempt depends on the policies installed on
1865*4f2df630SAndroid Build Coastguard Worker * Ti50. The result could be on of the following:
1866*4f2df630SAndroid Build Coastguard Worker *
1867*4f2df630SAndroid Build Coastguard Worker * - success (capability is successfully changed, or is already at the
1868*4f2df630SAndroid Build Coastguard Worker * requested level),
1869*4f2df630SAndroid Build Coastguard Worker * - various errors if setting the capability is not allowed or something
1870*4f2df630SAndroid Build Coastguard Worker * goes wrong on Ti50
1871*4f2df630SAndroid Build Coastguard Worker * - request for physical presence confirmation
1872*4f2df630SAndroid Build Coastguard Worker */
process_set_capabililty(struct transfer_descriptor * td,const char * parameter)1873*4f2df630SAndroid Build Coastguard Worker static enum exit_values process_set_capabililty(struct transfer_descriptor *td,
1874*4f2df630SAndroid Build Coastguard Worker const char *parameter)
1875*4f2df630SAndroid Build Coastguard Worker {
1876*4f2df630SAndroid Build Coastguard Worker const char *colon;
1877*4f2df630SAndroid Build Coastguard Worker size_t len;
1878*4f2df630SAndroid Build Coastguard Worker size_t cap_index;
1879*4f2df630SAndroid Build Coastguard Worker size_t i;
1880*4f2df630SAndroid Build Coastguard Worker uint8_t rc;
1881*4f2df630SAndroid Build Coastguard Worker const char *error_text;
1882*4f2df630SAndroid Build Coastguard Worker const char *cr50_err =
1883*4f2df630SAndroid Build Coastguard Worker "Note: setting capabilities not available on Cr50\n";
1884*4f2df630SAndroid Build Coastguard Worker /*
1885*4f2df630SAndroid Build Coastguard Worker * The payload is three bytes, command version, capability, and
1886*4f2df630SAndroid Build Coastguard Worker * desired state, all expressed as u8.
1887*4f2df630SAndroid Build Coastguard Worker */
1888*4f2df630SAndroid Build Coastguard Worker struct __attribute__((__packed__)) {
1889*4f2df630SAndroid Build Coastguard Worker uint8_t version;
1890*4f2df630SAndroid Build Coastguard Worker uint8_t cap;
1891*4f2df630SAndroid Build Coastguard Worker uint8_t value;
1892*4f2df630SAndroid Build Coastguard Worker } command;
1893*4f2df630SAndroid Build Coastguard Worker /*
1894*4f2df630SAndroid Build Coastguard Worker * Translation table of possible desired capabilities, Cr50 values
1895*4f2df630SAndroid Build Coastguard Worker * and duplicated in common/syscalls/src/ccd.rs::CcdCapState.
1896*4f2df630SAndroid Build Coastguard Worker */
1897*4f2df630SAndroid Build Coastguard Worker struct {
1898*4f2df630SAndroid Build Coastguard Worker const char *state_name;
1899*4f2df630SAndroid Build Coastguard Worker enum ccd_capability_state desired_state;
1900*4f2df630SAndroid Build Coastguard Worker } states[] = {
1901*4f2df630SAndroid Build Coastguard Worker { "default", CCD_CAP_STATE_DEFAULT },
1902*4f2df630SAndroid Build Coastguard Worker { "always", CCD_CAP_STATE_ALWAYS },
1903*4f2df630SAndroid Build Coastguard Worker { "if_opened", CCD_CAP_STATE_IF_OPENED },
1904*4f2df630SAndroid Build Coastguard Worker };
1905*4f2df630SAndroid Build Coastguard Worker
1906*4f2df630SAndroid Build Coastguard Worker /*
1907*4f2df630SAndroid Build Coastguard Worker * Possible responses from Ti50 when trying to modify AllowUnverifiedRo
1908*4f2df630SAndroid Build Coastguard Worker * capability. The values come from
1909*4f2df630SAndroid Build Coastguard Worker * common/libs/tpm2/extension/src/lib.rs::TpmvReturnCode.
1910*4f2df630SAndroid Build Coastguard Worker */
1911*4f2df630SAndroid Build Coastguard Worker enum set_allow_unverified_ro_responses {
1912*4f2df630SAndroid Build Coastguard Worker AUR_SUCCESS = 0,
1913*4f2df630SAndroid Build Coastguard Worker AUR_BOGUS_ARGS = 1,
1914*4f2df630SAndroid Build Coastguard Worker AUR_INTERNAL_ERROR = 6,
1915*4f2df630SAndroid Build Coastguard Worker AUR_NOT_ALLOWED = 7,
1916*4f2df630SAndroid Build Coastguard Worker AUR_IN_PROGRESS = 9,
1917*4f2df630SAndroid Build Coastguard Worker };
1918*4f2df630SAndroid Build Coastguard Worker
1919*4f2df630SAndroid Build Coastguard Worker /*
1920*4f2df630SAndroid Build Coastguard Worker * Validate the parameter, for starters make sure that the colon
1921*4f2df630SAndroid Build Coastguard Worker * symbol is present and is neither the first nor the last character
1922*4f2df630SAndroid Build Coastguard Worker * in the string.
1923*4f2df630SAndroid Build Coastguard Worker */
1924*4f2df630SAndroid Build Coastguard Worker colon = strchr(parameter, ':');
1925*4f2df630SAndroid Build Coastguard Worker if (!colon || (colon == parameter) || (colon[1] == '\0')) {
1926*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Misformatted capability parameter: %s\n",
1927*4f2df630SAndroid Build Coastguard Worker parameter);
1928*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1929*4f2df630SAndroid Build Coastguard Worker }
1930*4f2df630SAndroid Build Coastguard Worker
1931*4f2df630SAndroid Build Coastguard Worker /*
1932*4f2df630SAndroid Build Coastguard Worker * Find the capability index in the table, reject ambiguous
1933*4f2df630SAndroid Build Coastguard Worker * abbreviations.
1934*4f2df630SAndroid Build Coastguard Worker */
1935*4f2df630SAndroid Build Coastguard Worker len = colon - parameter;
1936*4f2df630SAndroid Build Coastguard Worker for (i = 0, cap_index = ARRAY_SIZE(ti50_cap_info);
1937*4f2df630SAndroid Build Coastguard Worker i < ARRAY_SIZE(ti50_cap_info); i++) {
1938*4f2df630SAndroid Build Coastguard Worker if (!strncasecmp(ti50_cap_info[i].name, parameter, len)) {
1939*4f2df630SAndroid Build Coastguard Worker if (cap_index != ARRAY_SIZE(ti50_cap_info)) {
1940*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Ambiguous capability name\n");
1941*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1942*4f2df630SAndroid Build Coastguard Worker }
1943*4f2df630SAndroid Build Coastguard Worker cap_index = i;
1944*4f2df630SAndroid Build Coastguard Worker }
1945*4f2df630SAndroid Build Coastguard Worker }
1946*4f2df630SAndroid Build Coastguard Worker if (cap_index == ARRAY_SIZE(ti50_cap_info)) {
1947*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unknown capability name\n%s", cr50_err);
1948*4f2df630SAndroid Build Coastguard Worker exit(update_error);
1949*4f2df630SAndroid Build Coastguard Worker }
1950*4f2df630SAndroid Build Coastguard Worker
1951*4f2df630SAndroid Build Coastguard Worker /* Calculate length of the desired value. */
1952*4f2df630SAndroid Build Coastguard Worker len = strlen(parameter) - len - 1;
1953*4f2df630SAndroid Build Coastguard Worker
1954*4f2df630SAndroid Build Coastguard Worker /* Find the value index in the table. */
1955*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(states); i++) {
1956*4f2df630SAndroid Build Coastguard Worker if (!strncasecmp(states[i].state_name, colon + 1, len))
1957*4f2df630SAndroid Build Coastguard Worker break;
1958*4f2df630SAndroid Build Coastguard Worker }
1959*4f2df630SAndroid Build Coastguard Worker if (i == ARRAY_SIZE(states)) {
1960*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unsupported capability value\n");
1961*4f2df630SAndroid Build Coastguard Worker return update_error;
1962*4f2df630SAndroid Build Coastguard Worker }
1963*4f2df630SAndroid Build Coastguard Worker
1964*4f2df630SAndroid Build Coastguard Worker /* Prepare and send vendor command to request setting capability. */
1965*4f2df630SAndroid Build Coastguard Worker command.version = CCD_VERSION;
1966*4f2df630SAndroid Build Coastguard Worker command.cap = (uint8_t)cap_index;
1967*4f2df630SAndroid Build Coastguard Worker command.value = (uint8_t)states[i].desired_state;
1968*4f2df630SAndroid Build Coastguard Worker
1969*4f2df630SAndroid Build Coastguard Worker i = 0;
1970*4f2df630SAndroid Build Coastguard Worker len = 1;
1971*4f2df630SAndroid Build Coastguard Worker send_vendor_command(td, VENDOR_CC_SET_CAPABILITY, &command,
1972*4f2df630SAndroid Build Coastguard Worker sizeof(command), &rc, &len);
1973*4f2df630SAndroid Build Coastguard Worker
1974*4f2df630SAndroid Build Coastguard Worker if (len != 1) {
1975*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected return message size %zd\n", len);
1976*4f2df630SAndroid Build Coastguard Worker if (len == 0)
1977*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "%s", cr50_err);
1978*4f2df630SAndroid Build Coastguard Worker return update_error;
1979*4f2df630SAndroid Build Coastguard Worker }
1980*4f2df630SAndroid Build Coastguard Worker
1981*4f2df630SAndroid Build Coastguard Worker switch (rc) {
1982*4f2df630SAndroid Build Coastguard Worker case AUR_IN_PROGRESS:
1983*4f2df630SAndroid Build Coastguard Worker /*
1984*4f2df630SAndroid Build Coastguard Worker * Physical presence poll is required, note fall through to
1985*4f2df630SAndroid Build Coastguard Worker * the next case.
1986*4f2df630SAndroid Build Coastguard Worker */
1987*4f2df630SAndroid Build Coastguard Worker poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_SET_CAPABILITY);
1988*4f2df630SAndroid Build Coastguard Worker case AUR_SUCCESS:
1989*4f2df630SAndroid Build Coastguard Worker return noop; /* All is well, no need to do anything. */
1990*4f2df630SAndroid Build Coastguard Worker case AUR_BOGUS_ARGS:
1991*4f2df630SAndroid Build Coastguard Worker error_text = "BogusArgs";
1992*4f2df630SAndroid Build Coastguard Worker break;
1993*4f2df630SAndroid Build Coastguard Worker case AUR_INTERNAL_ERROR:
1994*4f2df630SAndroid Build Coastguard Worker error_text = "InternalError";
1995*4f2df630SAndroid Build Coastguard Worker break;
1996*4f2df630SAndroid Build Coastguard Worker case AUR_NOT_ALLOWED:
1997*4f2df630SAndroid Build Coastguard Worker error_text = "NotAllowed";
1998*4f2df630SAndroid Build Coastguard Worker break;
1999*4f2df630SAndroid Build Coastguard Worker default:
2000*4f2df630SAndroid Build Coastguard Worker error_text = "Unknown";
2001*4f2df630SAndroid Build Coastguard Worker break;
2002*4f2df630SAndroid Build Coastguard Worker }
2003*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Got error %d(%s)\n", rc, error_text);
2004*4f2df630SAndroid Build Coastguard Worker return update_error;
2005*4f2df630SAndroid Build Coastguard Worker }
2006*4f2df630SAndroid Build Coastguard Worker
process_erase_ap_ro_hash(struct transfer_descriptor * td)2007*4f2df630SAndroid Build Coastguard Worker static void process_erase_ap_ro_hash(struct transfer_descriptor *td)
2008*4f2df630SAndroid Build Coastguard Worker {
2009*4f2df630SAndroid Build Coastguard Worker /* Try erasing AP RO hash, could fail if board ID is programmed. */
2010*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
2011*4f2df630SAndroid Build Coastguard Worker uint8_t response;
2012*4f2df630SAndroid Build Coastguard Worker size_t response_size;
2013*4f2df630SAndroid Build Coastguard Worker char error_details[64];
2014*4f2df630SAndroid Build Coastguard Worker
2015*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
2016*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SEED_AP_RO_CHECK, NULL, 0,
2017*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
2018*4f2df630SAndroid Build Coastguard Worker if (!rv) {
2019*4f2df630SAndroid Build Coastguard Worker printf("AP RO hash erased\n");
2020*4f2df630SAndroid Build Coastguard Worker exit(0);
2021*4f2df630SAndroid Build Coastguard Worker }
2022*4f2df630SAndroid Build Coastguard Worker
2023*4f2df630SAndroid Build Coastguard Worker if (response_size == sizeof(response)) {
2024*4f2df630SAndroid Build Coastguard Worker switch (response) {
2025*4f2df630SAndroid Build Coastguard Worker case ARCVE_FLASH_ERASE_FAILED:
2026*4f2df630SAndroid Build Coastguard Worker snprintf(error_details, sizeof(error_details),
2027*4f2df630SAndroid Build Coastguard Worker "erase failure");
2028*4f2df630SAndroid Build Coastguard Worker break;
2029*4f2df630SAndroid Build Coastguard Worker case ARCVE_BID_PROGRAMMED:
2030*4f2df630SAndroid Build Coastguard Worker snprintf(error_details, sizeof(error_details),
2031*4f2df630SAndroid Build Coastguard Worker "BID already programmed");
2032*4f2df630SAndroid Build Coastguard Worker break;
2033*4f2df630SAndroid Build Coastguard Worker default:
2034*4f2df630SAndroid Build Coastguard Worker snprintf(error_details, sizeof(error_details),
2035*4f2df630SAndroid Build Coastguard Worker "Unexpected error rc %d, response %d", rv,
2036*4f2df630SAndroid Build Coastguard Worker response);
2037*4f2df630SAndroid Build Coastguard Worker break;
2038*4f2df630SAndroid Build Coastguard Worker }
2039*4f2df630SAndroid Build Coastguard Worker } else {
2040*4f2df630SAndroid Build Coastguard Worker snprintf(error_details, sizeof(error_details),
2041*4f2df630SAndroid Build Coastguard Worker "misconfigured response, rc=%d, size %zd", rv,
2042*4f2df630SAndroid Build Coastguard Worker response_size);
2043*4f2df630SAndroid Build Coastguard Worker }
2044*4f2df630SAndroid Build Coastguard Worker
2045*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: %s\n", error_details);
2046*4f2df630SAndroid Build Coastguard Worker
2047*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2048*4f2df630SAndroid Build Coastguard Worker }
2049*4f2df630SAndroid Build Coastguard Worker
generate_reset_request(struct transfer_descriptor * td)2050*4f2df630SAndroid Build Coastguard Worker static void generate_reset_request(struct transfer_descriptor *td)
2051*4f2df630SAndroid Build Coastguard Worker {
2052*4f2df630SAndroid Build Coastguard Worker size_t response_size;
2053*4f2df630SAndroid Build Coastguard Worker uint8_t response;
2054*4f2df630SAndroid Build Coastguard Worker uint16_t subcommand;
2055*4f2df630SAndroid Build Coastguard Worker uint8_t command_body[2]; /* Max command body size. */
2056*4f2df630SAndroid Build Coastguard Worker size_t command_body_size;
2057*4f2df630SAndroid Build Coastguard Worker const char *reset_type;
2058*4f2df630SAndroid Build Coastguard Worker int rv;
2059*4f2df630SAndroid Build Coastguard Worker
2060*4f2df630SAndroid Build Coastguard Worker if (protocol_version < 6) {
2061*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer) {
2062*4f2df630SAndroid Build Coastguard Worker /*
2063*4f2df630SAndroid Build Coastguard Worker * Send a second stop request, which should reboot
2064*4f2df630SAndroid Build Coastguard Worker * without replying.
2065*4f2df630SAndroid Build Coastguard Worker */
2066*4f2df630SAndroid Build Coastguard Worker send_done(&td->uep);
2067*4f2df630SAndroid Build Coastguard Worker }
2068*4f2df630SAndroid Build Coastguard Worker /* Nothing we can do over /dev/tpm0 running versions below 6. */
2069*4f2df630SAndroid Build Coastguard Worker return;
2070*4f2df630SAndroid Build Coastguard Worker }
2071*4f2df630SAndroid Build Coastguard Worker
2072*4f2df630SAndroid Build Coastguard Worker /*
2073*4f2df630SAndroid Build Coastguard Worker * If this is an upstart request, don't post a request now. The target
2074*4f2df630SAndroid Build Coastguard Worker * should handle it on the next reboot.
2075*4f2df630SAndroid Build Coastguard Worker */
2076*4f2df630SAndroid Build Coastguard Worker if (td->upstart_mode)
2077*4f2df630SAndroid Build Coastguard Worker return;
2078*4f2df630SAndroid Build Coastguard Worker
2079*4f2df630SAndroid Build Coastguard Worker /*
2080*4f2df630SAndroid Build Coastguard Worker * If the user explicitly wants it, request post reset instead of
2081*4f2df630SAndroid Build Coastguard Worker * immediate reset. In this case next time the target reboots, the GSC
2082*4f2df630SAndroid Build Coastguard Worker * will reboot as well, and will consider running the uploaded code.
2083*4f2df630SAndroid Build Coastguard Worker *
2084*4f2df630SAndroid Build Coastguard Worker * Otherwise, to reset the target the host is supposed to send the
2085*4f2df630SAndroid Build Coastguard Worker * command to enable the uploaded image disabled by default.
2086*4f2df630SAndroid Build Coastguard Worker */
2087*4f2df630SAndroid Build Coastguard Worker response_size = 1;
2088*4f2df630SAndroid Build Coastguard Worker if (td->post_reset) {
2089*4f2df630SAndroid Build Coastguard Worker subcommand = EXTENSION_POST_RESET;
2090*4f2df630SAndroid Build Coastguard Worker command_body_size = 0;
2091*4f2df630SAndroid Build Coastguard Worker reset_type = "posted";
2092*4f2df630SAndroid Build Coastguard Worker } else {
2093*4f2df630SAndroid Build Coastguard Worker subcommand = VENDOR_CC_TURN_UPDATE_ON;
2094*4f2df630SAndroid Build Coastguard Worker command_body_size = sizeof(command_body);
2095*4f2df630SAndroid Build Coastguard Worker command_body[0] = 0;
2096*4f2df630SAndroid Build Coastguard Worker command_body[1] = 100; /* Reset in 100 ms. */
2097*4f2df630SAndroid Build Coastguard Worker reset_type = "requested";
2098*4f2df630SAndroid Build Coastguard Worker }
2099*4f2df630SAndroid Build Coastguard Worker
2100*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, subcommand, command_body,
2101*4f2df630SAndroid Build Coastguard Worker command_body_size, &response, &response_size);
2102*4f2df630SAndroid Build Coastguard Worker
2103*4f2df630SAndroid Build Coastguard Worker if (rv) {
2104*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "*%s: Error %#x\n", __func__, rv);
2105*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2106*4f2df630SAndroid Build Coastguard Worker }
2107*4f2df630SAndroid Build Coastguard Worker printf("reboot %s\n", reset_type);
2108*4f2df630SAndroid Build Coastguard Worker }
2109*4f2df630SAndroid Build Coastguard Worker
2110*4f2df630SAndroid Build Coastguard Worker /* Forward to correct SHA implementation based on image type */
sha_init(EVP_MD_CTX * ctx)2111*4f2df630SAndroid Build Coastguard Worker static void sha_init(EVP_MD_CTX *ctx)
2112*4f2df630SAndroid Build Coastguard Worker {
2113*4f2df630SAndroid Build Coastguard Worker if (gsc_dev == GSC_DEVICE_H1)
2114*4f2df630SAndroid Build Coastguard Worker EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
2115*4f2df630SAndroid Build Coastguard Worker else if (gsc_dev == GSC_DEVICE_DT || gsc_dev == GSC_DEVICE_NT)
2116*4f2df630SAndroid Build Coastguard Worker EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
2117*4f2df630SAndroid Build Coastguard Worker else {
2118*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: unknown GSC device type\n");
2119*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2120*4f2df630SAndroid Build Coastguard Worker }
2121*4f2df630SAndroid Build Coastguard Worker }
2122*4f2df630SAndroid Build Coastguard Worker
2123*4f2df630SAndroid Build Coastguard Worker /* Forward to correct SHA implementation based on image type */
sha_update(EVP_MD_CTX * ctx,const void * data,size_t len)2124*4f2df630SAndroid Build Coastguard Worker static void sha_update(EVP_MD_CTX *ctx, const void *data, size_t len)
2125*4f2df630SAndroid Build Coastguard Worker {
2126*4f2df630SAndroid Build Coastguard Worker EVP_DigestUpdate(ctx, data, len);
2127*4f2df630SAndroid Build Coastguard Worker }
2128*4f2df630SAndroid Build Coastguard Worker
2129*4f2df630SAndroid Build Coastguard Worker /* Forward to correct SHA implementation based on image type */
sha_final_into_block_digest(EVP_MD_CTX * ctx,void * block_digest,size_t size)2130*4f2df630SAndroid Build Coastguard Worker static void sha_final_into_block_digest(EVP_MD_CTX *ctx, void *block_digest,
2131*4f2df630SAndroid Build Coastguard Worker size_t size)
2132*4f2df630SAndroid Build Coastguard Worker {
2133*4f2df630SAndroid Build Coastguard Worker /* Big enough for either hash algo */
2134*4f2df630SAndroid Build Coastguard Worker uint8_t full_digest[SHA256_DIGEST_LENGTH];
2135*4f2df630SAndroid Build Coastguard Worker unsigned int length;
2136*4f2df630SAndroid Build Coastguard Worker
2137*4f2df630SAndroid Build Coastguard Worker EVP_DigestFinal(ctx, full_digest, &length);
2138*4f2df630SAndroid Build Coastguard Worker
2139*4f2df630SAndroid Build Coastguard Worker /* Copy out the smaller of the 2 byte counts. */
2140*4f2df630SAndroid Build Coastguard Worker memcpy(block_digest, full_digest, MIN(size, length));
2141*4f2df630SAndroid Build Coastguard Worker }
2142*4f2df630SAndroid Build Coastguard Worker
2143*4f2df630SAndroid Build Coastguard Worker /*
2144*4f2df630SAndroid Build Coastguard Worker * Machine output is formatted as "key=value", one key-value pair per line, and
2145*4f2df630SAndroid Build Coastguard Worker * parsed by other programs (e.g., debugd). The value part should be specified
2146*4f2df630SAndroid Build Coastguard Worker * in the printf-like way. For example:
2147*4f2df630SAndroid Build Coastguard Worker *
2148*4f2df630SAndroid Build Coastguard Worker * print_machine_output("date", "%d/%d/%d", 2018, 1, 1),
2149*4f2df630SAndroid Build Coastguard Worker *
2150*4f2df630SAndroid Build Coastguard Worker * which outputs this line in console:
2151*4f2df630SAndroid Build Coastguard Worker *
2152*4f2df630SAndroid Build Coastguard Worker * date=2018/1/1
2153*4f2df630SAndroid Build Coastguard Worker *
2154*4f2df630SAndroid Build Coastguard Worker * The key part should not contain '=' or newline. The value part may contain
2155*4f2df630SAndroid Build Coastguard Worker * special characters like spaces, quotes, brackets, but not newlines. The
2156*4f2df630SAndroid Build Coastguard Worker * newline character means end of value.
2157*4f2df630SAndroid Build Coastguard Worker *
2158*4f2df630SAndroid Build Coastguard Worker * Any output format change in this function may require similar changes on the
2159*4f2df630SAndroid Build Coastguard Worker * programs that are using this gsctool.
2160*4f2df630SAndroid Build Coastguard Worker */
print_machine_output(const char * key,const char * format,...)2161*4f2df630SAndroid Build Coastguard Worker __attribute__((__format__(__printf__, 2, 3))) static void print_machine_output(
2162*4f2df630SAndroid Build Coastguard Worker const char *key, const char *format, ...)
2163*4f2df630SAndroid Build Coastguard Worker {
2164*4f2df630SAndroid Build Coastguard Worker va_list args;
2165*4f2df630SAndroid Build Coastguard Worker
2166*4f2df630SAndroid Build Coastguard Worker if (strchr(key, '=') != NULL || strchr(key, '\n') != NULL) {
2167*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
2168*4f2df630SAndroid Build Coastguard Worker "Error: key %s contains '=' or a newline character.\n",
2169*4f2df630SAndroid Build Coastguard Worker key);
2170*4f2df630SAndroid Build Coastguard Worker return;
2171*4f2df630SAndroid Build Coastguard Worker }
2172*4f2df630SAndroid Build Coastguard Worker
2173*4f2df630SAndroid Build Coastguard Worker if (strchr(format, '\n') != NULL) {
2174*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
2175*4f2df630SAndroid Build Coastguard Worker "Error: value format %s contains a newline character. "
2176*4f2df630SAndroid Build Coastguard Worker "\n",
2177*4f2df630SAndroid Build Coastguard Worker format);
2178*4f2df630SAndroid Build Coastguard Worker return;
2179*4f2df630SAndroid Build Coastguard Worker }
2180*4f2df630SAndroid Build Coastguard Worker
2181*4f2df630SAndroid Build Coastguard Worker va_start(args, format);
2182*4f2df630SAndroid Build Coastguard Worker
2183*4f2df630SAndroid Build Coastguard Worker printf("%s=", key);
2184*4f2df630SAndroid Build Coastguard Worker vprintf(format, args);
2185*4f2df630SAndroid Build Coastguard Worker printf("\n");
2186*4f2df630SAndroid Build Coastguard Worker
2187*4f2df630SAndroid Build Coastguard Worker va_end(args);
2188*4f2df630SAndroid Build Coastguard Worker }
2189*4f2df630SAndroid Build Coastguard Worker
2190*4f2df630SAndroid Build Coastguard Worker /*
2191*4f2df630SAndroid Build Coastguard Worker * Prints out the header, including FW versions and board IDs, of the given
2192*4f2df630SAndroid Build Coastguard Worker * image. Output in a machine-friendly format if show_machine_output is true.
2193*4f2df630SAndroid Build Coastguard Worker */
show_headers_versions(const struct image * image,bool show_machine_output)2194*4f2df630SAndroid Build Coastguard Worker static int show_headers_versions(const struct image *image,
2195*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
2196*4f2df630SAndroid Build Coastguard Worker {
2197*4f2df630SAndroid Build Coastguard Worker /*
2198*4f2df630SAndroid Build Coastguard Worker * There are 2 FW slots in an image, and each slot has 2 sections, RO
2199*4f2df630SAndroid Build Coastguard Worker * and RW. The 2 slots should have identical FW versions and board
2200*4f2df630SAndroid Build Coastguard Worker * IDs.
2201*4f2df630SAndroid Build Coastguard Worker */
2202*4f2df630SAndroid Build Coastguard Worker const size_t kNumSlots = 2;
2203*4f2df630SAndroid Build Coastguard Worker const size_t kNumSectionsPerSlot = 2;
2204*4f2df630SAndroid Build Coastguard Worker const struct section_t *sections = image->sections;
2205*4f2df630SAndroid Build Coastguard Worker
2206*4f2df630SAndroid Build Coastguard Worker /*
2207*4f2df630SAndroid Build Coastguard Worker * String representation of FW version (<epoch>:<major>:<minor>), one
2208*4f2df630SAndroid Build Coastguard Worker * string for each FW section.
2209*4f2df630SAndroid Build Coastguard Worker */
2210*4f2df630SAndroid Build Coastguard Worker char ro_fw_ver[kNumSlots][MAX_FW_VER_LENGTH];
2211*4f2df630SAndroid Build Coastguard Worker char rw_fw_ver[kNumSlots][MAX_FW_VER_LENGTH];
2212*4f2df630SAndroid Build Coastguard Worker
2213*4f2df630SAndroid Build Coastguard Worker uint32_t dev_id0_[kNumSlots];
2214*4f2df630SAndroid Build Coastguard Worker uint32_t dev_id1_[kNumSlots];
2215*4f2df630SAndroid Build Coastguard Worker uint32_t print_devid = 0;
2216*4f2df630SAndroid Build Coastguard Worker
2217*4f2df630SAndroid Build Coastguard Worker struct board_id {
2218*4f2df630SAndroid Build Coastguard Worker uint32_t id;
2219*4f2df630SAndroid Build Coastguard Worker uint32_t mask;
2220*4f2df630SAndroid Build Coastguard Worker uint32_t flags;
2221*4f2df630SAndroid Build Coastguard Worker } bid[kNumSlots];
2222*4f2df630SAndroid Build Coastguard Worker
2223*4f2df630SAndroid Build Coastguard Worker char bid_string[kNumSlots][MAX_BOARD_ID_LENGTH];
2224*4f2df630SAndroid Build Coastguard Worker
2225*4f2df630SAndroid Build Coastguard Worker size_t i;
2226*4f2df630SAndroid Build Coastguard Worker
2227*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < NUM_SECTIONS; i++) {
2228*4f2df630SAndroid Build Coastguard Worker const struct typed_image_header h =
2229*4f2df630SAndroid Build Coastguard Worker as_header(image, sections[i].offset);
2230*4f2df630SAndroid Build Coastguard Worker const size_t slot_idx = i / kNumSectionsPerSlot;
2231*4f2df630SAndroid Build Coastguard Worker
2232*4f2df630SAndroid Build Coastguard Worker uint32_t cur_bid;
2233*4f2df630SAndroid Build Coastguard Worker size_t j;
2234*4f2df630SAndroid Build Coastguard Worker
2235*4f2df630SAndroid Build Coastguard Worker if (i == RO_A || i == RO_B) {
2236*4f2df630SAndroid Build Coastguard Worker /* RO. */
2237*4f2df630SAndroid Build Coastguard Worker snprintf(ro_fw_ver[slot_idx], MAX_FW_VER_LENGTH,
2238*4f2df630SAndroid Build Coastguard Worker "%d.%d.%d", sections[i].shv.epoch,
2239*4f2df630SAndroid Build Coastguard Worker sections[i].shv.major, sections[i].shv.minor);
2240*4f2df630SAndroid Build Coastguard Worker /* No need to read board ID in an RO section. */
2241*4f2df630SAndroid Build Coastguard Worker continue;
2242*4f2df630SAndroid Build Coastguard Worker } else {
2243*4f2df630SAndroid Build Coastguard Worker /* RW. */
2244*4f2df630SAndroid Build Coastguard Worker snprintf(rw_fw_ver[slot_idx], MAX_FW_VER_LENGTH,
2245*4f2df630SAndroid Build Coastguard Worker "%d.%d.%d", sections[i].shv.epoch,
2246*4f2df630SAndroid Build Coastguard Worker sections[i].shv.major, sections[i].shv.minor);
2247*4f2df630SAndroid Build Coastguard Worker }
2248*4f2df630SAndroid Build Coastguard Worker
2249*4f2df630SAndroid Build Coastguard Worker /*
2250*4f2df630SAndroid Build Coastguard Worker * For RW sections, retrieves the board ID fields' contents,
2251*4f2df630SAndroid Build Coastguard Worker * which are stored XORed with a padding value.
2252*4f2df630SAndroid Build Coastguard Worker */
2253*4f2df630SAndroid Build Coastguard Worker if (h.type == GSC_DEVICE_H1 || h.type == GSC_DEVICE_DT) {
2254*4f2df630SAndroid Build Coastguard Worker bid[slot_idx].id = h.h->board_id_type ^
2255*4f2df630SAndroid Build Coastguard Worker SIGNED_HEADER_PADDING;
2256*4f2df630SAndroid Build Coastguard Worker bid[slot_idx].mask = h.h->board_id_type_mask ^
2257*4f2df630SAndroid Build Coastguard Worker SIGNED_HEADER_PADDING;
2258*4f2df630SAndroid Build Coastguard Worker bid[slot_idx].flags = h.h->board_id_flags ^
2259*4f2df630SAndroid Build Coastguard Worker SIGNED_HEADER_PADDING;
2260*4f2df630SAndroid Build Coastguard Worker
2261*4f2df630SAndroid Build Coastguard Worker dev_id0_[slot_idx] = h.h->dev_id0_;
2262*4f2df630SAndroid Build Coastguard Worker dev_id1_[slot_idx] = h.h->dev_id1_;
2263*4f2df630SAndroid Build Coastguard Worker } else if (h.type == GSC_DEVICE_NT) {
2264*4f2df630SAndroid Build Coastguard Worker /*
2265*4f2df630SAndroid Build Coastguard Worker * TODO(b/341348812): Get BID info from signed manifest
2266*4f2df630SAndroid Build Coastguard Worker * header.
2267*4f2df630SAndroid Build Coastguard Worker */
2268*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "BID info not support on NT yet.\n");
2269*4f2df630SAndroid Build Coastguard Worker bid[slot_idx].id = -1;
2270*4f2df630SAndroid Build Coastguard Worker bid[slot_idx].mask = -1;
2271*4f2df630SAndroid Build Coastguard Worker bid[slot_idx].flags = -1;
2272*4f2df630SAndroid Build Coastguard Worker
2273*4f2df630SAndroid Build Coastguard Worker /* Check if devid constraints are being enforced */
2274*4f2df630SAndroid Build Coastguard Worker if (h.m->constraint_selector_bits & 0x6) {
2275*4f2df630SAndroid Build Coastguard Worker dev_id0_[slot_idx] =
2276*4f2df630SAndroid Build Coastguard Worker h.m->constraint_device_id[1];
2277*4f2df630SAndroid Build Coastguard Worker dev_id1_[slot_idx] =
2278*4f2df630SAndroid Build Coastguard Worker h.m->constraint_device_id[2];
2279*4f2df630SAndroid Build Coastguard Worker } else {
2280*4f2df630SAndroid Build Coastguard Worker dev_id0_[slot_idx] = 0;
2281*4f2df630SAndroid Build Coastguard Worker dev_id1_[slot_idx] = 0;
2282*4f2df630SAndroid Build Coastguard Worker }
2283*4f2df630SAndroid Build Coastguard Worker } else {
2284*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nERROR: Unknown image type.\n");
2285*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2286*4f2df630SAndroid Build Coastguard Worker }
2287*4f2df630SAndroid Build Coastguard Worker /* Print the devid if any slot has a non-zero devid. */
2288*4f2df630SAndroid Build Coastguard Worker print_devid |= dev_id0_[slot_idx] | dev_id1_[slot_idx];
2289*4f2df630SAndroid Build Coastguard Worker /*
2290*4f2df630SAndroid Build Coastguard Worker * If board ID is a 4-uppercase-letter string (as it ought to
2291*4f2df630SAndroid Build Coastguard Worker * be), print it as 4 letters, otherwise print it as an 8-digit
2292*4f2df630SAndroid Build Coastguard Worker * hex.
2293*4f2df630SAndroid Build Coastguard Worker */
2294*4f2df630SAndroid Build Coastguard Worker cur_bid = bid[slot_idx].id;
2295*4f2df630SAndroid Build Coastguard Worker for (j = 0; j < sizeof(cur_bid); ++j)
2296*4f2df630SAndroid Build Coastguard Worker if (!isupper(((const char *)&cur_bid)[j]))
2297*4f2df630SAndroid Build Coastguard Worker break;
2298*4f2df630SAndroid Build Coastguard Worker
2299*4f2df630SAndroid Build Coastguard Worker if (j == sizeof(cur_bid)) {
2300*4f2df630SAndroid Build Coastguard Worker cur_bid = be32toh(cur_bid);
2301*4f2df630SAndroid Build Coastguard Worker snprintf(bid_string[slot_idx], MAX_BOARD_ID_LENGTH,
2302*4f2df630SAndroid Build Coastguard Worker "%.4s", (const char *)&cur_bid);
2303*4f2df630SAndroid Build Coastguard Worker } else {
2304*4f2df630SAndroid Build Coastguard Worker snprintf(bid_string[slot_idx], MAX_BOARD_ID_LENGTH,
2305*4f2df630SAndroid Build Coastguard Worker "%08x", cur_bid);
2306*4f2df630SAndroid Build Coastguard Worker }
2307*4f2df630SAndroid Build Coastguard Worker }
2308*4f2df630SAndroid Build Coastguard Worker
2309*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
2310*4f2df630SAndroid Build Coastguard Worker print_machine_output("IMAGE_RO_FW_VER", "%s", ro_fw_ver[0]);
2311*4f2df630SAndroid Build Coastguard Worker print_machine_output("IMAGE_RW_FW_VER", "%s", rw_fw_ver[0]);
2312*4f2df630SAndroid Build Coastguard Worker print_machine_output("IMAGE_BID_STRING", "%s", bid_string[0]);
2313*4f2df630SAndroid Build Coastguard Worker print_machine_output("IMAGE_BID_MASK", "%08x", bid[0].mask);
2314*4f2df630SAndroid Build Coastguard Worker print_machine_output("IMAGE_BID_FLAGS", "%08x", bid[0].flags);
2315*4f2df630SAndroid Build Coastguard Worker } else {
2316*4f2df630SAndroid Build Coastguard Worker printf("RO_A:%s RW_A:%s[%s:%08x:%08x] ", ro_fw_ver[0],
2317*4f2df630SAndroid Build Coastguard Worker rw_fw_ver[0], bid_string[0], bid[0].mask, bid[0].flags);
2318*4f2df630SAndroid Build Coastguard Worker printf("RO_B:%s RW_B:%s[%s:%08x:%08x]\n", ro_fw_ver[1],
2319*4f2df630SAndroid Build Coastguard Worker rw_fw_ver[1], bid_string[1], bid[1].mask, bid[1].flags);
2320*4f2df630SAndroid Build Coastguard Worker
2321*4f2df630SAndroid Build Coastguard Worker if (print_devid) {
2322*4f2df630SAndroid Build Coastguard Worker printf("DEVID: 0x%08x 0x%08x", dev_id0_[0],
2323*4f2df630SAndroid Build Coastguard Worker dev_id1_[0]);
2324*4f2df630SAndroid Build Coastguard Worker /*
2325*4f2df630SAndroid Build Coastguard Worker * Only print the second devid if it's different.
2326*4f2df630SAndroid Build Coastguard Worker * Separate the devids with tabs, so it's easier to
2327*4f2df630SAndroid Build Coastguard Worker * read.
2328*4f2df630SAndroid Build Coastguard Worker */
2329*4f2df630SAndroid Build Coastguard Worker if (dev_id0_[0] != dev_id0_[1] ||
2330*4f2df630SAndroid Build Coastguard Worker dev_id1_[0] != dev_id1_[1])
2331*4f2df630SAndroid Build Coastguard Worker printf("\t\t\t\tDEVID_B: 0x%08x 0x%08x",
2332*4f2df630SAndroid Build Coastguard Worker dev_id0_[1], dev_id1_[1]);
2333*4f2df630SAndroid Build Coastguard Worker printf("\n");
2334*4f2df630SAndroid Build Coastguard Worker }
2335*4f2df630SAndroid Build Coastguard Worker }
2336*4f2df630SAndroid Build Coastguard Worker
2337*4f2df630SAndroid Build Coastguard Worker return 0;
2338*4f2df630SAndroid Build Coastguard Worker }
2339*4f2df630SAndroid Build Coastguard Worker
2340*4f2df630SAndroid Build Coastguard Worker /*
2341*4f2df630SAndroid Build Coastguard Worker * The default flag value will allow to run images built for any hardware
2342*4f2df630SAndroid Build Coastguard Worker * generation of a particular board ID.
2343*4f2df630SAndroid Build Coastguard Worker */
2344*4f2df630SAndroid Build Coastguard Worker #define DEFAULT_BOARD_ID_FLAG 0xff00
parse_bid(const char * opt,struct board_id * bid,enum board_id_action * bid_action)2345*4f2df630SAndroid Build Coastguard Worker static int parse_bid(const char *opt, struct board_id *bid,
2346*4f2df630SAndroid Build Coastguard Worker enum board_id_action *bid_action)
2347*4f2df630SAndroid Build Coastguard Worker {
2348*4f2df630SAndroid Build Coastguard Worker char *e;
2349*4f2df630SAndroid Build Coastguard Worker const char *param2;
2350*4f2df630SAndroid Build Coastguard Worker size_t param1_length;
2351*4f2df630SAndroid Build Coastguard Worker
2352*4f2df630SAndroid Build Coastguard Worker if (!opt) {
2353*4f2df630SAndroid Build Coastguard Worker *bid_action = bid_get;
2354*4f2df630SAndroid Build Coastguard Worker return 1;
2355*4f2df630SAndroid Build Coastguard Worker }
2356*4f2df630SAndroid Build Coastguard Worker
2357*4f2df630SAndroid Build Coastguard Worker /* Set it here to make bailing out easier later. */
2358*4f2df630SAndroid Build Coastguard Worker bid->flags = DEFAULT_BOARD_ID_FLAG;
2359*4f2df630SAndroid Build Coastguard Worker
2360*4f2df630SAndroid Build Coastguard Worker *bid_action = bid_set; /* Ignored by caller on errors. */
2361*4f2df630SAndroid Build Coastguard Worker
2362*4f2df630SAndroid Build Coastguard Worker /*
2363*4f2df630SAndroid Build Coastguard Worker * Pointer to the optional second component of the command line
2364*4f2df630SAndroid Build Coastguard Worker * parameter, when present - separated by a colon.
2365*4f2df630SAndroid Build Coastguard Worker */
2366*4f2df630SAndroid Build Coastguard Worker param2 = strchr(opt, ':');
2367*4f2df630SAndroid Build Coastguard Worker if (param2) {
2368*4f2df630SAndroid Build Coastguard Worker param1_length = param2 - opt;
2369*4f2df630SAndroid Build Coastguard Worker param2++;
2370*4f2df630SAndroid Build Coastguard Worker if (!*param2)
2371*4f2df630SAndroid Build Coastguard Worker return 0; /* Empty second parameter. */
2372*4f2df630SAndroid Build Coastguard Worker } else {
2373*4f2df630SAndroid Build Coastguard Worker param1_length = strlen(opt);
2374*4f2df630SAndroid Build Coastguard Worker }
2375*4f2df630SAndroid Build Coastguard Worker
2376*4f2df630SAndroid Build Coastguard Worker if (!param1_length)
2377*4f2df630SAndroid Build Coastguard Worker return 0; /* Colon is the first character of the string? */
2378*4f2df630SAndroid Build Coastguard Worker
2379*4f2df630SAndroid Build Coastguard Worker if (param1_length <= 4) {
2380*4f2df630SAndroid Build Coastguard Worker unsigned i;
2381*4f2df630SAndroid Build Coastguard Worker
2382*4f2df630SAndroid Build Coastguard Worker /* Input must be a symbolic board name. */
2383*4f2df630SAndroid Build Coastguard Worker bid->type = 0;
2384*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < param1_length; i++)
2385*4f2df630SAndroid Build Coastguard Worker bid->type = (bid->type << 8) | opt[i];
2386*4f2df630SAndroid Build Coastguard Worker } else {
2387*4f2df630SAndroid Build Coastguard Worker bid->type = (uint32_t)strtoul(opt, &e, 0);
2388*4f2df630SAndroid Build Coastguard Worker if ((param2 && (*e != ':')) || (!param2 && *e))
2389*4f2df630SAndroid Build Coastguard Worker return 0;
2390*4f2df630SAndroid Build Coastguard Worker }
2391*4f2df630SAndroid Build Coastguard Worker
2392*4f2df630SAndroid Build Coastguard Worker if (param2) {
2393*4f2df630SAndroid Build Coastguard Worker bid->flags = (uint32_t)strtoul(param2, &e, 0);
2394*4f2df630SAndroid Build Coastguard Worker if (*e)
2395*4f2df630SAndroid Build Coastguard Worker return 0;
2396*4f2df630SAndroid Build Coastguard Worker }
2397*4f2df630SAndroid Build Coastguard Worker
2398*4f2df630SAndroid Build Coastguard Worker return 1;
2399*4f2df630SAndroid Build Coastguard Worker }
2400*4f2df630SAndroid Build Coastguard Worker
2401*4f2df630SAndroid Build Coastguard Worker /*
2402*4f2df630SAndroid Build Coastguard Worker * Reads a two-character hexadecimal byte from a string. If the string is
2403*4f2df630SAndroid Build Coastguard Worker * ill-formed, returns 0. Otherwise, |byte| contains the byte value and the
2404*4f2df630SAndroid Build Coastguard Worker * return value is non-zero.
2405*4f2df630SAndroid Build Coastguard Worker */
read_hex_byte(const char * s,uint8_t * byte)2406*4f2df630SAndroid Build Coastguard Worker static int read_hex_byte(const char *s, uint8_t *byte)
2407*4f2df630SAndroid Build Coastguard Worker {
2408*4f2df630SAndroid Build Coastguard Worker uint8_t b = 0;
2409*4f2df630SAndroid Build Coastguard Worker for (const char *end = s + 2; s < end; ++s) {
2410*4f2df630SAndroid Build Coastguard Worker if (*s >= '0' && *s <= '9')
2411*4f2df630SAndroid Build Coastguard Worker b = b * 16 + *s - '0';
2412*4f2df630SAndroid Build Coastguard Worker else if (*s >= 'A' && *s <= 'F')
2413*4f2df630SAndroid Build Coastguard Worker b = b * 16 + 10 + *s - 'A';
2414*4f2df630SAndroid Build Coastguard Worker else if (*s >= 'a' && *s <= 'f')
2415*4f2df630SAndroid Build Coastguard Worker b = b * 16 + 10 + *s - 'a';
2416*4f2df630SAndroid Build Coastguard Worker else
2417*4f2df630SAndroid Build Coastguard Worker return 0;
2418*4f2df630SAndroid Build Coastguard Worker }
2419*4f2df630SAndroid Build Coastguard Worker *byte = b;
2420*4f2df630SAndroid Build Coastguard Worker return 1;
2421*4f2df630SAndroid Build Coastguard Worker }
2422*4f2df630SAndroid Build Coastguard Worker
parse_sn_bits(const char * opt,uint8_t * sn_bits)2423*4f2df630SAndroid Build Coastguard Worker static int parse_sn_bits(const char *opt, uint8_t *sn_bits)
2424*4f2df630SAndroid Build Coastguard Worker {
2425*4f2df630SAndroid Build Coastguard Worker size_t len = strlen(opt);
2426*4f2df630SAndroid Build Coastguard Worker
2427*4f2df630SAndroid Build Coastguard Worker if (!strncmp(opt, "0x", 2)) {
2428*4f2df630SAndroid Build Coastguard Worker opt += 2;
2429*4f2df630SAndroid Build Coastguard Worker len -= 2;
2430*4f2df630SAndroid Build Coastguard Worker }
2431*4f2df630SAndroid Build Coastguard Worker if (len != SN_BITS_SIZE * 2)
2432*4f2df630SAndroid Build Coastguard Worker return 0;
2433*4f2df630SAndroid Build Coastguard Worker
2434*4f2df630SAndroid Build Coastguard Worker for (int i = 0; i < SN_BITS_SIZE; ++i, opt += 2)
2435*4f2df630SAndroid Build Coastguard Worker if (!read_hex_byte(opt, sn_bits++))
2436*4f2df630SAndroid Build Coastguard Worker return 0;
2437*4f2df630SAndroid Build Coastguard Worker
2438*4f2df630SAndroid Build Coastguard Worker return 1;
2439*4f2df630SAndroid Build Coastguard Worker }
2440*4f2df630SAndroid Build Coastguard Worker
parse_sn_inc_rma(const char * opt,uint8_t * arg)2441*4f2df630SAndroid Build Coastguard Worker static int parse_sn_inc_rma(const char *opt, uint8_t *arg)
2442*4f2df630SAndroid Build Coastguard Worker {
2443*4f2df630SAndroid Build Coastguard Worker uint32_t inc;
2444*4f2df630SAndroid Build Coastguard Worker char *e;
2445*4f2df630SAndroid Build Coastguard Worker
2446*4f2df630SAndroid Build Coastguard Worker inc = (uint32_t)strtoul(opt, &e, 0);
2447*4f2df630SAndroid Build Coastguard Worker
2448*4f2df630SAndroid Build Coastguard Worker if (opt == e || *e != '\0' || inc > 7)
2449*4f2df630SAndroid Build Coastguard Worker return 0;
2450*4f2df630SAndroid Build Coastguard Worker
2451*4f2df630SAndroid Build Coastguard Worker *arg = inc;
2452*4f2df630SAndroid Build Coastguard Worker return 1;
2453*4f2df630SAndroid Build Coastguard Worker }
2454*4f2df630SAndroid Build Coastguard Worker
common_process_password(struct transfer_descriptor * td,enum ccd_vendor_subcommands subcmd)2455*4f2df630SAndroid Build Coastguard Worker static uint32_t common_process_password(struct transfer_descriptor *td,
2456*4f2df630SAndroid Build Coastguard Worker enum ccd_vendor_subcommands subcmd)
2457*4f2df630SAndroid Build Coastguard Worker {
2458*4f2df630SAndroid Build Coastguard Worker size_t response_size;
2459*4f2df630SAndroid Build Coastguard Worker uint8_t response;
2460*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
2461*4f2df630SAndroid Build Coastguard Worker char *password = NULL;
2462*4f2df630SAndroid Build Coastguard Worker char *password_copy = NULL;
2463*4f2df630SAndroid Build Coastguard Worker ssize_t copy_len;
2464*4f2df630SAndroid Build Coastguard Worker ssize_t len;
2465*4f2df630SAndroid Build Coastguard Worker size_t zero = 0;
2466*4f2df630SAndroid Build Coastguard Worker struct termios oldattr, newattr;
2467*4f2df630SAndroid Build Coastguard Worker
2468*4f2df630SAndroid Build Coastguard Worker /* Suppress command line echo while password is being entered. */
2469*4f2df630SAndroid Build Coastguard Worker tcgetattr(STDIN_FILENO, &oldattr);
2470*4f2df630SAndroid Build Coastguard Worker newattr = oldattr;
2471*4f2df630SAndroid Build Coastguard Worker newattr.c_lflag &= ~ECHO;
2472*4f2df630SAndroid Build Coastguard Worker newattr.c_lflag |= (ICANON | ECHONL);
2473*4f2df630SAndroid Build Coastguard Worker tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
2474*4f2df630SAndroid Build Coastguard Worker
2475*4f2df630SAndroid Build Coastguard Worker /* With command line echo suppressed request password entry twice. */
2476*4f2df630SAndroid Build Coastguard Worker printf("Enter password:");
2477*4f2df630SAndroid Build Coastguard Worker len = getline(&password, &zero, stdin);
2478*4f2df630SAndroid Build Coastguard Worker printf("Re-enter password:");
2479*4f2df630SAndroid Build Coastguard Worker zero = 0;
2480*4f2df630SAndroid Build Coastguard Worker copy_len = getline(&password_copy, &zero, stdin);
2481*4f2df630SAndroid Build Coastguard Worker
2482*4f2df630SAndroid Build Coastguard Worker /* Restore command line echo. */
2483*4f2df630SAndroid Build Coastguard Worker tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
2484*4f2df630SAndroid Build Coastguard Worker
2485*4f2df630SAndroid Build Coastguard Worker /* Empty password will still have the newline. */
2486*4f2df630SAndroid Build Coastguard Worker if ((len <= 1) || !password_copy || (copy_len != len)) {
2487*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error reading password\n");
2488*4f2df630SAndroid Build Coastguard Worker if (password)
2489*4f2df630SAndroid Build Coastguard Worker free(password);
2490*4f2df630SAndroid Build Coastguard Worker if (password_copy)
2491*4f2df630SAndroid Build Coastguard Worker free(password_copy);
2492*4f2df630SAndroid Build Coastguard Worker if ((copy_len >= 0) && (len >= 0) && (copy_len != len))
2493*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Password length mismatch\n");
2494*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2495*4f2df630SAndroid Build Coastguard Worker }
2496*4f2df630SAndroid Build Coastguard Worker
2497*4f2df630SAndroid Build Coastguard Worker /* Compare the two inputs. */
2498*4f2df630SAndroid Build Coastguard Worker if (strcmp(password, password_copy)) {
2499*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Entered passwords don't match\n");
2500*4f2df630SAndroid Build Coastguard Worker free(password);
2501*4f2df630SAndroid Build Coastguard Worker free(password_copy);
2502*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2503*4f2df630SAndroid Build Coastguard Worker }
2504*4f2df630SAndroid Build Coastguard Worker
2505*4f2df630SAndroid Build Coastguard Worker /*
2506*4f2df630SAndroid Build Coastguard Worker * Ok, we have a password, let's move it in the buffer to overwrite
2507*4f2df630SAndroid Build Coastguard Worker * the newline and free a byte to prepend the subcommand code.
2508*4f2df630SAndroid Build Coastguard Worker */
2509*4f2df630SAndroid Build Coastguard Worker memmove(password + 1, password, len - 1);
2510*4f2df630SAndroid Build Coastguard Worker password[0] = subcmd;
2511*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
2512*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_CCD, password, len, &response,
2513*4f2df630SAndroid Build Coastguard Worker &response_size);
2514*4f2df630SAndroid Build Coastguard Worker free(password);
2515*4f2df630SAndroid Build Coastguard Worker free(password_copy);
2516*4f2df630SAndroid Build Coastguard Worker
2517*4f2df630SAndroid Build Coastguard Worker if ((rv != VENDOR_RC_SUCCESS) && (rv != VENDOR_RC_IN_PROGRESS))
2518*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error sending password: rv %d, response %d\n",
2519*4f2df630SAndroid Build Coastguard Worker rv, response_size ? response : 0);
2520*4f2df630SAndroid Build Coastguard Worker
2521*4f2df630SAndroid Build Coastguard Worker return rv;
2522*4f2df630SAndroid Build Coastguard Worker }
2523*4f2df630SAndroid Build Coastguard Worker
process_password(struct transfer_descriptor * td)2524*4f2df630SAndroid Build Coastguard Worker static void process_password(struct transfer_descriptor *td)
2525*4f2df630SAndroid Build Coastguard Worker {
2526*4f2df630SAndroid Build Coastguard Worker if (common_process_password(td, CCDV_PASSWORD) == VENDOR_RC_SUCCESS)
2527*4f2df630SAndroid Build Coastguard Worker return;
2528*4f2df630SAndroid Build Coastguard Worker
2529*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2530*4f2df630SAndroid Build Coastguard Worker }
2531*4f2df630SAndroid Build Coastguard Worker
poll_for_pp(struct transfer_descriptor * td,uint16_t command,uint8_t poll_type)2532*4f2df630SAndroid Build Coastguard Worker void poll_for_pp(struct transfer_descriptor *td, uint16_t command,
2533*4f2df630SAndroid Build Coastguard Worker uint8_t poll_type)
2534*4f2df630SAndroid Build Coastguard Worker {
2535*4f2df630SAndroid Build Coastguard Worker uint8_t response;
2536*4f2df630SAndroid Build Coastguard Worker uint8_t prev_response;
2537*4f2df630SAndroid Build Coastguard Worker size_t response_size;
2538*4f2df630SAndroid Build Coastguard Worker int rv;
2539*4f2df630SAndroid Build Coastguard Worker
2540*4f2df630SAndroid Build Coastguard Worker prev_response = ~0; /* Guaranteed invalid value. */
2541*4f2df630SAndroid Build Coastguard Worker
2542*4f2df630SAndroid Build Coastguard Worker while (1) {
2543*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
2544*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, command, &poll_type,
2545*4f2df630SAndroid Build Coastguard Worker sizeof(poll_type), &response,
2546*4f2df630SAndroid Build Coastguard Worker &response_size);
2547*4f2df630SAndroid Build Coastguard Worker
2548*4f2df630SAndroid Build Coastguard Worker if (((rv != VENDOR_RC_SUCCESS) &&
2549*4f2df630SAndroid Build Coastguard Worker (rv != VENDOR_RC_IN_PROGRESS)) ||
2550*4f2df630SAndroid Build Coastguard Worker (response_size != 1)) {
2551*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: rv %d, response %d\n", rv,
2552*4f2df630SAndroid Build Coastguard Worker response_size ? response : 0);
2553*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2554*4f2df630SAndroid Build Coastguard Worker }
2555*4f2df630SAndroid Build Coastguard Worker
2556*4f2df630SAndroid Build Coastguard Worker if (response == CCD_PP_DONE) {
2557*4f2df630SAndroid Build Coastguard Worker printf("PP Done!\n");
2558*4f2df630SAndroid Build Coastguard Worker return;
2559*4f2df630SAndroid Build Coastguard Worker }
2560*4f2df630SAndroid Build Coastguard Worker
2561*4f2df630SAndroid Build Coastguard Worker if (response == CCD_PP_CLOSED) {
2562*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
2563*4f2df630SAndroid Build Coastguard Worker "Error: Physical presence check timeout!\n");
2564*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2565*4f2df630SAndroid Build Coastguard Worker }
2566*4f2df630SAndroid Build Coastguard Worker
2567*4f2df630SAndroid Build Coastguard Worker if (response == CCD_PP_AWAITING_PRESS) {
2568*4f2df630SAndroid Build Coastguard Worker printf("Press PP button now!\n");
2569*4f2df630SAndroid Build Coastguard Worker } else if (response == CCD_PP_BETWEEN_PRESSES) {
2570*4f2df630SAndroid Build Coastguard Worker if (prev_response != response)
2571*4f2df630SAndroid Build Coastguard Worker printf("Another press will be required!\n");
2572*4f2df630SAndroid Build Coastguard Worker } else {
2573*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: unknown poll result %d\n",
2574*4f2df630SAndroid Build Coastguard Worker response);
2575*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2576*4f2df630SAndroid Build Coastguard Worker }
2577*4f2df630SAndroid Build Coastguard Worker prev_response = response;
2578*4f2df630SAndroid Build Coastguard Worker
2579*4f2df630SAndroid Build Coastguard Worker usleep(500 * 1000); /* Poll every half a second. */
2580*4f2df630SAndroid Build Coastguard Worker }
2581*4f2df630SAndroid Build Coastguard Worker }
2582*4f2df630SAndroid Build Coastguard Worker
2583*4f2df630SAndroid Build Coastguard Worker /* Determine the longest capability name found in the passed in table. */
longest_cap_name_len(const struct ccd_capability_info * table,size_t count)2584*4f2df630SAndroid Build Coastguard Worker static size_t longest_cap_name_len(const struct ccd_capability_info *table,
2585*4f2df630SAndroid Build Coastguard Worker size_t count)
2586*4f2df630SAndroid Build Coastguard Worker {
2587*4f2df630SAndroid Build Coastguard Worker size_t i;
2588*4f2df630SAndroid Build Coastguard Worker size_t result = 0;
2589*4f2df630SAndroid Build Coastguard Worker
2590*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < count; i++) {
2591*4f2df630SAndroid Build Coastguard Worker size_t this_size;
2592*4f2df630SAndroid Build Coastguard Worker
2593*4f2df630SAndroid Build Coastguard Worker this_size = strlen(table[i].name);
2594*4f2df630SAndroid Build Coastguard Worker if (this_size > result)
2595*4f2df630SAndroid Build Coastguard Worker result = this_size;
2596*4f2df630SAndroid Build Coastguard Worker }
2597*4f2df630SAndroid Build Coastguard Worker return result;
2598*4f2df630SAndroid Build Coastguard Worker }
2599*4f2df630SAndroid Build Coastguard Worker
2600*4f2df630SAndroid Build Coastguard Worker /*
2601*4f2df630SAndroid Build Coastguard Worker * Print the passed in capability name padded to the longest length determined
2602*4f2df630SAndroid Build Coastguard Worker * earlier.
2603*4f2df630SAndroid Build Coastguard Worker */
print_aligned(const char * name,size_t field_size)2604*4f2df630SAndroid Build Coastguard Worker static void print_aligned(const char *name, size_t field_size)
2605*4f2df630SAndroid Build Coastguard Worker {
2606*4f2df630SAndroid Build Coastguard Worker size_t name_len;
2607*4f2df630SAndroid Build Coastguard Worker
2608*4f2df630SAndroid Build Coastguard Worker name_len = strlen(name);
2609*4f2df630SAndroid Build Coastguard Worker
2610*4f2df630SAndroid Build Coastguard Worker printf("%s", name);
2611*4f2df630SAndroid Build Coastguard Worker while (name_len < field_size) {
2612*4f2df630SAndroid Build Coastguard Worker printf(" ");
2613*4f2df630SAndroid Build Coastguard Worker name_len++;
2614*4f2df630SAndroid Build Coastguard Worker }
2615*4f2df630SAndroid Build Coastguard Worker }
2616*4f2df630SAndroid Build Coastguard Worker
2617*4f2df630SAndroid Build Coastguard Worker /*
2618*4f2df630SAndroid Build Coastguard Worker * Translates "AnExampleTPMString" into "AN_EXAMPLE_TPM_STRING". Note that
2619*4f2df630SAndroid Build Coastguard Worker * output must be large enough to contain a 150%-sized string of input.
2620*4f2df630SAndroid Build Coastguard Worker */
to_upper_underscore(const char * input,char * output)2621*4f2df630SAndroid Build Coastguard Worker static void to_upper_underscore(const char *input, char *output)
2622*4f2df630SAndroid Build Coastguard Worker {
2623*4f2df630SAndroid Build Coastguard Worker bool first_char = true;
2624*4f2df630SAndroid Build Coastguard Worker bool needs_underscore = false;
2625*4f2df630SAndroid Build Coastguard Worker
2626*4f2df630SAndroid Build Coastguard Worker while (*input != '\0') {
2627*4f2df630SAndroid Build Coastguard Worker *output = toupper(*input);
2628*4f2df630SAndroid Build Coastguard Worker /*
2629*4f2df630SAndroid Build Coastguard Worker * If we encounter an upper case char in the input, we may need
2630*4f2df630SAndroid Build Coastguard Worker * to add an underscore in the output before (re)writing the
2631*4f2df630SAndroid Build Coastguard Worker * output char
2632*4f2df630SAndroid Build Coastguard Worker */
2633*4f2df630SAndroid Build Coastguard Worker if (*output == *input) {
2634*4f2df630SAndroid Build Coastguard Worker /*
2635*4f2df630SAndroid Build Coastguard Worker * See if the next input letter is lower case, that
2636*4f2df630SAndroid Build Coastguard Worker * means this uppercase letter needs a '_' before it.
2637*4f2df630SAndroid Build Coastguard Worker */
2638*4f2df630SAndroid Build Coastguard Worker if (islower(*(input + 1)) && !first_char)
2639*4f2df630SAndroid Build Coastguard Worker needs_underscore = true;
2640*4f2df630SAndroid Build Coastguard Worker if (needs_underscore) {
2641*4f2df630SAndroid Build Coastguard Worker needs_underscore = false;
2642*4f2df630SAndroid Build Coastguard Worker *output++ = '_';
2643*4f2df630SAndroid Build Coastguard Worker *output = *input;
2644*4f2df630SAndroid Build Coastguard Worker }
2645*4f2df630SAndroid Build Coastguard Worker } else {
2646*4f2df630SAndroid Build Coastguard Worker /*
2647*4f2df630SAndroid Build Coastguard Worker * We encountered a lower case, so the next upper case
2648*4f2df630SAndroid Build Coastguard Worker * should have a '_' before it
2649*4f2df630SAndroid Build Coastguard Worker */
2650*4f2df630SAndroid Build Coastguard Worker needs_underscore = true;
2651*4f2df630SAndroid Build Coastguard Worker }
2652*4f2df630SAndroid Build Coastguard Worker first_char = false;
2653*4f2df630SAndroid Build Coastguard Worker input++;
2654*4f2df630SAndroid Build Coastguard Worker output++;
2655*4f2df630SAndroid Build Coastguard Worker }
2656*4f2df630SAndroid Build Coastguard Worker *output = '\0';
2657*4f2df630SAndroid Build Coastguard Worker }
2658*4f2df630SAndroid Build Coastguard Worker
2659*4f2df630SAndroid Build Coastguard Worker /*
2660*4f2df630SAndroid Build Coastguard Worker * Ensure that the CCD info response is well formed otherwise exits. Upon return
2661*4f2df630SAndroid Build Coastguard Worker * the ccd_info variable will contain the structured ccd info response and the
2662*4f2df630SAndroid Build Coastguard Worker * return value is the version of ccd info to parse with (e.g. 0 for cr50 and
2663*4f2df630SAndroid Build Coastguard Worker * 1 for ti50).
2664*4f2df630SAndroid Build Coastguard Worker */
validate_into_ccd_info_response(void * response,size_t response_size,struct ccd_info_response * ccd_info)2665*4f2df630SAndroid Build Coastguard Worker static uint32_t validate_into_ccd_info_response(
2666*4f2df630SAndroid Build Coastguard Worker void *response, size_t response_size,
2667*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response *ccd_info)
2668*4f2df630SAndroid Build Coastguard Worker {
2669*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response_header ccd_info_header;
2670*4f2df630SAndroid Build Coastguard Worker size_t i;
2671*4f2df630SAndroid Build Coastguard Worker uint32_t ccd_info_version;
2672*4f2df630SAndroid Build Coastguard Worker
2673*4f2df630SAndroid Build Coastguard Worker if (response_size < sizeof(ccd_info_header)) {
2674*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "CCD info response too short %zd\n",
2675*4f2df630SAndroid Build Coastguard Worker response_size);
2676*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2677*4f2df630SAndroid Build Coastguard Worker }
2678*4f2df630SAndroid Build Coastguard Worker
2679*4f2df630SAndroid Build Coastguard Worker /* Let's check if this is a newer version response. */
2680*4f2df630SAndroid Build Coastguard Worker memcpy(&ccd_info_header, response, sizeof(ccd_info_header));
2681*4f2df630SAndroid Build Coastguard Worker if ((ccd_info_header.ccd_magic == CCD_INFO_MAGIC) &&
2682*4f2df630SAndroid Build Coastguard Worker (ccd_info_header.ccd_size == response_size) &&
2683*4f2df630SAndroid Build Coastguard Worker /* Verify that payload size matches ccd_info size. */
2684*4f2df630SAndroid Build Coastguard Worker ((response_size - sizeof(ccd_info_header)) == sizeof(*ccd_info))) {
2685*4f2df630SAndroid Build Coastguard Worker ccd_info_version = ccd_info_header.ccd_version;
2686*4f2df630SAndroid Build Coastguard Worker memcpy(ccd_info,
2687*4f2df630SAndroid Build Coastguard Worker (uint8_t *)response +
2688*4f2df630SAndroid Build Coastguard Worker sizeof(struct ccd_info_response_header),
2689*4f2df630SAndroid Build Coastguard Worker sizeof(*ccd_info));
2690*4f2df630SAndroid Build Coastguard Worker /*
2691*4f2df630SAndroid Build Coastguard Worker * V1 CCD info structure uses little endian for transmission.
2692*4f2df630SAndroid Build Coastguard Worker * No need to update to host endianness since it is already LE.
2693*4f2df630SAndroid Build Coastguard Worker */
2694*4f2df630SAndroid Build Coastguard Worker } else if (response_size == CCD_INFO_V0_SIZE) {
2695*4f2df630SAndroid Build Coastguard Worker ccd_info_version = 0; /* Default, Cr50 case. */
2696*4f2df630SAndroid Build Coastguard Worker memcpy(ccd_info, response, sizeof(*ccd_info));
2697*4f2df630SAndroid Build Coastguard Worker /*
2698*4f2df630SAndroid Build Coastguard Worker * V0 CCD info structure uses big endian for transmission.
2699*4f2df630SAndroid Build Coastguard Worker * Update fields to host endianness.
2700*4f2df630SAndroid Build Coastguard Worker */
2701*4f2df630SAndroid Build Coastguard Worker ccd_info->ccd_flags = be32toh(ccd_info->ccd_flags);
2702*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_SIZE(ccd_info->ccd_caps_current); i++) {
2703*4f2df630SAndroid Build Coastguard Worker ccd_info->ccd_caps_current[i] =
2704*4f2df630SAndroid Build Coastguard Worker be32toh(ccd_info->ccd_caps_current[i]);
2705*4f2df630SAndroid Build Coastguard Worker ccd_info->ccd_caps_defaults[i] =
2706*4f2df630SAndroid Build Coastguard Worker be32toh(ccd_info->ccd_caps_defaults[i]);
2707*4f2df630SAndroid Build Coastguard Worker }
2708*4f2df630SAndroid Build Coastguard Worker } else {
2709*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected CCD info response size %zd\n",
2710*4f2df630SAndroid Build Coastguard Worker response_size);
2711*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2712*4f2df630SAndroid Build Coastguard Worker }
2713*4f2df630SAndroid Build Coastguard Worker
2714*4f2df630SAndroid Build Coastguard Worker return ccd_info_version;
2715*4f2df630SAndroid Build Coastguard Worker }
2716*4f2df630SAndroid Build Coastguard Worker
print_ccd_info(void * response,size_t response_size,bool show_machine_output)2717*4f2df630SAndroid Build Coastguard Worker static void print_ccd_info(void *response, size_t response_size,
2718*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
2719*4f2df630SAndroid Build Coastguard Worker {
2720*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response ccd_info;
2721*4f2df630SAndroid Build Coastguard Worker size_t i;
2722*4f2df630SAndroid Build Coastguard Worker const struct ccd_capability_info cr50_cap_info[] = CAP_INFO_DATA;
2723*4f2df630SAndroid Build Coastguard Worker const char *state_names[] = CCD_STATE_NAMES;
2724*4f2df630SAndroid Build Coastguard Worker const char *cap_state_names[] = CCD_CAP_STATE_NAMES;
2725*4f2df630SAndroid Build Coastguard Worker uint32_t caps_bitmap = 0;
2726*4f2df630SAndroid Build Coastguard Worker uint32_t ccd_info_version;
2727*4f2df630SAndroid Build Coastguard Worker
2728*4f2df630SAndroid Build Coastguard Worker /*
2729*4f2df630SAndroid Build Coastguard Worker * CCD info structure is different for different GSCs. Two layouts are
2730*4f2df630SAndroid Build Coastguard Worker * defined at this time, version 0 (Cr50) and version 1 (Ti50). The
2731*4f2df630SAndroid Build Coastguard Worker * array below indexed by version number provides access to version
2732*4f2df630SAndroid Build Coastguard Worker * specific information about the layout.
2733*4f2df630SAndroid Build Coastguard Worker */
2734*4f2df630SAndroid Build Coastguard Worker const struct {
2735*4f2df630SAndroid Build Coastguard Worker size_t cap_count;
2736*4f2df630SAndroid Build Coastguard Worker const struct ccd_capability_info *info_table;
2737*4f2df630SAndroid Build Coastguard Worker } version_to_ccd[] = {
2738*4f2df630SAndroid Build Coastguard Worker { CR50_CCD_CAP_COUNT, cr50_cap_info },
2739*4f2df630SAndroid Build Coastguard Worker { TI50_CCD_CAP_COUNT, ti50_cap_info },
2740*4f2df630SAndroid Build Coastguard Worker };
2741*4f2df630SAndroid Build Coastguard Worker
2742*4f2df630SAndroid Build Coastguard Worker /* Run time determined properties of the CCD info table. */
2743*4f2df630SAndroid Build Coastguard Worker size_t gsc_cap_count;
2744*4f2df630SAndroid Build Coastguard Worker const struct ccd_capability_info *gsc_capability_info;
2745*4f2df630SAndroid Build Coastguard Worker size_t name_column_width;
2746*4f2df630SAndroid Build Coastguard Worker
2747*4f2df630SAndroid Build Coastguard Worker ccd_info_version = validate_into_ccd_info_response(
2748*4f2df630SAndroid Build Coastguard Worker response, response_size, &ccd_info);
2749*4f2df630SAndroid Build Coastguard Worker
2750*4f2df630SAndroid Build Coastguard Worker if (ccd_info_version >= ARRAY_SIZE(version_to_ccd)) {
2751*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unsupported CCD info version number %d\n",
2752*4f2df630SAndroid Build Coastguard Worker ccd_info_version);
2753*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2754*4f2df630SAndroid Build Coastguard Worker }
2755*4f2df630SAndroid Build Coastguard Worker
2756*4f2df630SAndroid Build Coastguard Worker /* Now report CCD state on the console. */
2757*4f2df630SAndroid Build Coastguard Worker const char *const state = ccd_info.ccd_state > ARRAY_SIZE(state_names) ?
2758*4f2df630SAndroid Build Coastguard Worker "Error" :
2759*4f2df630SAndroid Build Coastguard Worker state_names[ccd_info.ccd_state];
2760*4f2df630SAndroid Build Coastguard Worker const char *const password = (ccd_info.ccd_indicator_bitmap &
2761*4f2df630SAndroid Build Coastguard Worker CCD_INDICATOR_BIT_HAS_PASSWORD) ?
2762*4f2df630SAndroid Build Coastguard Worker "Set" :
2763*4f2df630SAndroid Build Coastguard Worker "None";
2764*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
2765*4f2df630SAndroid Build Coastguard Worker print_machine_output("STATE", "%s", state);
2766*4f2df630SAndroid Build Coastguard Worker print_machine_output("PASSWORD", "%s", password);
2767*4f2df630SAndroid Build Coastguard Worker print_machine_output("CCD_FLAGS", "%#06x", ccd_info.ccd_flags);
2768*4f2df630SAndroid Build Coastguard Worker print_machine_output(
2769*4f2df630SAndroid Build Coastguard Worker "CCD_FLAG_TESTLAB_MODE", "%c",
2770*4f2df630SAndroid Build Coastguard Worker (ccd_info.ccd_flags & CCD_FLAG_TEST_LAB) ? 'Y' : 'N');
2771*4f2df630SAndroid Build Coastguard Worker print_machine_output("CCD_FLAG_FACTORY_MODE", "%c",
2772*4f2df630SAndroid Build Coastguard Worker (ccd_info.ccd_flags &
2773*4f2df630SAndroid Build Coastguard Worker CCD_FLAG_FACTORY_MODE_ENABLED) ?
2774*4f2df630SAndroid Build Coastguard Worker 'Y' :
2775*4f2df630SAndroid Build Coastguard Worker 'N');
2776*4f2df630SAndroid Build Coastguard Worker } else {
2777*4f2df630SAndroid Build Coastguard Worker printf("State: %s\n", state);
2778*4f2df630SAndroid Build Coastguard Worker printf("Password: %s\n", password);
2779*4f2df630SAndroid Build Coastguard Worker printf("Flags: %#06x\n", ccd_info.ccd_flags);
2780*4f2df630SAndroid Build Coastguard Worker printf("Capabilities, current and default:\n");
2781*4f2df630SAndroid Build Coastguard Worker }
2782*4f2df630SAndroid Build Coastguard Worker
2783*4f2df630SAndroid Build Coastguard Worker gsc_cap_count = version_to_ccd[ccd_info_version].cap_count;
2784*4f2df630SAndroid Build Coastguard Worker gsc_capability_info = version_to_ccd[ccd_info_version].info_table;
2785*4f2df630SAndroid Build Coastguard Worker name_column_width =
2786*4f2df630SAndroid Build Coastguard Worker longest_cap_name_len(gsc_capability_info, gsc_cap_count) + 1;
2787*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < gsc_cap_count; i++) {
2788*4f2df630SAndroid Build Coastguard Worker int is_enabled;
2789*4f2df630SAndroid Build Coastguard Worker int index;
2790*4f2df630SAndroid Build Coastguard Worker int shift;
2791*4f2df630SAndroid Build Coastguard Worker int cap_current;
2792*4f2df630SAndroid Build Coastguard Worker int cap_default;
2793*4f2df630SAndroid Build Coastguard Worker
2794*4f2df630SAndroid Build Coastguard Worker index = i / (32 / CCD_CAP_BITS);
2795*4f2df630SAndroid Build Coastguard Worker shift = (i % (32 / CCD_CAP_BITS)) * CCD_CAP_BITS;
2796*4f2df630SAndroid Build Coastguard Worker
2797*4f2df630SAndroid Build Coastguard Worker cap_current = (ccd_info.ccd_caps_current[index] >> shift) &
2798*4f2df630SAndroid Build Coastguard Worker CCD_CAP_BITMASK;
2799*4f2df630SAndroid Build Coastguard Worker cap_default = (ccd_info.ccd_caps_defaults[index] >> shift) &
2800*4f2df630SAndroid Build Coastguard Worker CCD_CAP_BITMASK;
2801*4f2df630SAndroid Build Coastguard Worker
2802*4f2df630SAndroid Build Coastguard Worker if (ccd_info.ccd_force_disabled) {
2803*4f2df630SAndroid Build Coastguard Worker is_enabled = 0;
2804*4f2df630SAndroid Build Coastguard Worker } else {
2805*4f2df630SAndroid Build Coastguard Worker switch (cap_current) {
2806*4f2df630SAndroid Build Coastguard Worker case CCD_CAP_STATE_ALWAYS:
2807*4f2df630SAndroid Build Coastguard Worker is_enabled = 1;
2808*4f2df630SAndroid Build Coastguard Worker break;
2809*4f2df630SAndroid Build Coastguard Worker case CCD_CAP_STATE_UNLESS_LOCKED:
2810*4f2df630SAndroid Build Coastguard Worker is_enabled = (ccd_info.ccd_state !=
2811*4f2df630SAndroid Build Coastguard Worker CCD_STATE_LOCKED);
2812*4f2df630SAndroid Build Coastguard Worker break;
2813*4f2df630SAndroid Build Coastguard Worker default:
2814*4f2df630SAndroid Build Coastguard Worker is_enabled = (ccd_info.ccd_state ==
2815*4f2df630SAndroid Build Coastguard Worker CCD_STATE_OPENED);
2816*4f2df630SAndroid Build Coastguard Worker break;
2817*4f2df630SAndroid Build Coastguard Worker }
2818*4f2df630SAndroid Build Coastguard Worker }
2819*4f2df630SAndroid Build Coastguard Worker
2820*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
2821*4f2df630SAndroid Build Coastguard Worker char upper[80];
2822*4f2df630SAndroid Build Coastguard Worker
2823*4f2df630SAndroid Build Coastguard Worker to_upper_underscore(gsc_capability_info[i].name, upper);
2824*4f2df630SAndroid Build Coastguard Worker print_machine_output(upper, "%c",
2825*4f2df630SAndroid Build Coastguard Worker is_enabled ? 'Y' : 'N');
2826*4f2df630SAndroid Build Coastguard Worker } else {
2827*4f2df630SAndroid Build Coastguard Worker printf(" ");
2828*4f2df630SAndroid Build Coastguard Worker print_aligned(gsc_capability_info[i].name,
2829*4f2df630SAndroid Build Coastguard Worker name_column_width);
2830*4f2df630SAndroid Build Coastguard Worker printf("%c %s", is_enabled ? 'Y' : '-',
2831*4f2df630SAndroid Build Coastguard Worker cap_state_names[cap_current]);
2832*4f2df630SAndroid Build Coastguard Worker
2833*4f2df630SAndroid Build Coastguard Worker if (cap_current != cap_default)
2834*4f2df630SAndroid Build Coastguard Worker printf(" (%s)", cap_state_names[cap_default]);
2835*4f2df630SAndroid Build Coastguard Worker
2836*4f2df630SAndroid Build Coastguard Worker printf("\n");
2837*4f2df630SAndroid Build Coastguard Worker }
2838*4f2df630SAndroid Build Coastguard Worker
2839*4f2df630SAndroid Build Coastguard Worker if (is_enabled)
2840*4f2df630SAndroid Build Coastguard Worker caps_bitmap |= (1 << i);
2841*4f2df630SAndroid Build Coastguard Worker }
2842*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
2843*4f2df630SAndroid Build Coastguard Worker print_machine_output("CCD_CAPS_BITMAP", "%#x", caps_bitmap);
2844*4f2df630SAndroid Build Coastguard Worker print_machine_output("CAPABILITY_MODIFIED", "%c",
2845*4f2df630SAndroid Build Coastguard Worker (ccd_info.ccd_indicator_bitmap &
2846*4f2df630SAndroid Build Coastguard Worker CCD_INDICATOR_BIT_ALL_CAPS_DEFAULT) ?
2847*4f2df630SAndroid Build Coastguard Worker 'N' :
2848*4f2df630SAndroid Build Coastguard Worker 'Y');
2849*4f2df630SAndroid Build Coastguard Worker print_machine_output("INITIAL_FACTORY_MODE", "%c",
2850*4f2df630SAndroid Build Coastguard Worker (ccd_info.ccd_indicator_bitmap &
2851*4f2df630SAndroid Build Coastguard Worker CCD_INDICATOR_BIT_INITIAL_FACTORY_MODE) ?
2852*4f2df630SAndroid Build Coastguard Worker 'Y' :
2853*4f2df630SAndroid Build Coastguard Worker 'N');
2854*4f2df630SAndroid Build Coastguard Worker
2855*4f2df630SAndroid Build Coastguard Worker } else {
2856*4f2df630SAndroid Build Coastguard Worker printf("CCD caps bitmap: %#x\n", caps_bitmap);
2857*4f2df630SAndroid Build Coastguard Worker printf("Capabilities are %s.\n",
2858*4f2df630SAndroid Build Coastguard Worker (ccd_info.ccd_indicator_bitmap &
2859*4f2df630SAndroid Build Coastguard Worker CCD_INDICATOR_BIT_ALL_CAPS_DEFAULT) ?
2860*4f2df630SAndroid Build Coastguard Worker "default" :
2861*4f2df630SAndroid Build Coastguard Worker "modified");
2862*4f2df630SAndroid Build Coastguard Worker if (ccd_info.ccd_indicator_bitmap &
2863*4f2df630SAndroid Build Coastguard Worker CCD_INDICATOR_BIT_INITIAL_FACTORY_MODE) {
2864*4f2df630SAndroid Build Coastguard Worker printf("Chip factory mode.");
2865*4f2df630SAndroid Build Coastguard Worker }
2866*4f2df630SAndroid Build Coastguard Worker }
2867*4f2df630SAndroid Build Coastguard Worker }
2868*4f2df630SAndroid Build Coastguard Worker
process_ccd_state(struct transfer_descriptor * td,int ccd_unlock,int ccd_open,int ccd_lock,int ccd_info,bool show_machine_output)2869*4f2df630SAndroid Build Coastguard Worker static void process_ccd_state(struct transfer_descriptor *td, int ccd_unlock,
2870*4f2df630SAndroid Build Coastguard Worker int ccd_open, int ccd_lock, int ccd_info,
2871*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
2872*4f2df630SAndroid Build Coastguard Worker {
2873*4f2df630SAndroid Build Coastguard Worker uint8_t payload;
2874*4f2df630SAndroid Build Coastguard Worker /* Max possible response size is when ccd_info is requested. */
2875*4f2df630SAndroid Build Coastguard Worker uint8_t response[sizeof(struct ccd_info_response_packet)];
2876*4f2df630SAndroid Build Coastguard Worker size_t response_size;
2877*4f2df630SAndroid Build Coastguard Worker int rv;
2878*4f2df630SAndroid Build Coastguard Worker
2879*4f2df630SAndroid Build Coastguard Worker if (ccd_unlock)
2880*4f2df630SAndroid Build Coastguard Worker payload = CCDV_UNLOCK;
2881*4f2df630SAndroid Build Coastguard Worker else if (ccd_open)
2882*4f2df630SAndroid Build Coastguard Worker payload = CCDV_OPEN;
2883*4f2df630SAndroid Build Coastguard Worker else if (ccd_lock)
2884*4f2df630SAndroid Build Coastguard Worker payload = CCDV_LOCK;
2885*4f2df630SAndroid Build Coastguard Worker else
2886*4f2df630SAndroid Build Coastguard Worker payload = CCDV_GET_INFO;
2887*4f2df630SAndroid Build Coastguard Worker
2888*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
2889*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_CCD, &payload, sizeof(payload),
2890*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
2891*4f2df630SAndroid Build Coastguard Worker
2892*4f2df630SAndroid Build Coastguard Worker /*
2893*4f2df630SAndroid Build Coastguard Worker * If password is required - try sending the same subcommand
2894*4f2df630SAndroid Build Coastguard Worker * accompanied by user password.
2895*4f2df630SAndroid Build Coastguard Worker */
2896*4f2df630SAndroid Build Coastguard Worker if (rv == VENDOR_RC_PASSWORD_REQUIRED)
2897*4f2df630SAndroid Build Coastguard Worker rv = common_process_password(td, payload);
2898*4f2df630SAndroid Build Coastguard Worker
2899*4f2df630SAndroid Build Coastguard Worker if (rv == VENDOR_RC_SUCCESS) {
2900*4f2df630SAndroid Build Coastguard Worker if (ccd_info)
2901*4f2df630SAndroid Build Coastguard Worker print_ccd_info(response, response_size,
2902*4f2df630SAndroid Build Coastguard Worker show_machine_output);
2903*4f2df630SAndroid Build Coastguard Worker return;
2904*4f2df630SAndroid Build Coastguard Worker }
2905*4f2df630SAndroid Build Coastguard Worker
2906*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_IN_PROGRESS) {
2907*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: rv %d, response %d\n", rv,
2908*4f2df630SAndroid Build Coastguard Worker response_size ? response[0] : 0);
2909*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2910*4f2df630SAndroid Build Coastguard Worker }
2911*4f2df630SAndroid Build Coastguard Worker
2912*4f2df630SAndroid Build Coastguard Worker /*
2913*4f2df630SAndroid Build Coastguard Worker * Physical presence process started, poll for the state the user
2914*4f2df630SAndroid Build Coastguard Worker * asked for. Only two subcommands would return 'IN_PROGRESS'.
2915*4f2df630SAndroid Build Coastguard Worker */
2916*4f2df630SAndroid Build Coastguard Worker if (ccd_unlock)
2917*4f2df630SAndroid Build Coastguard Worker poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_UNLOCK);
2918*4f2df630SAndroid Build Coastguard Worker else
2919*4f2df630SAndroid Build Coastguard Worker poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_OPEN);
2920*4f2df630SAndroid Build Coastguard Worker }
2921*4f2df630SAndroid Build Coastguard Worker
2922*4f2df630SAndroid Build Coastguard Worker /*
2923*4f2df630SAndroid Build Coastguard Worker * Ensure that the AllowUnverifiedRO capability is set to always. If called for
2924*4f2df630SAndroid Build Coastguard Worker * Cr50 (which does not have this capability), the program will exit instead.
2925*4f2df630SAndroid Build Coastguard Worker */
is_unverified_ro_allowed(struct transfer_descriptor * td)2926*4f2df630SAndroid Build Coastguard Worker static bool is_unverified_ro_allowed(struct transfer_descriptor *td)
2927*4f2df630SAndroid Build Coastguard Worker {
2928*4f2df630SAndroid Build Coastguard Worker uint8_t cmd = CCDV_GET_INFO;
2929*4f2df630SAndroid Build Coastguard Worker /* Max possible response size is when ccd_info is requested. */
2930*4f2df630SAndroid Build Coastguard Worker uint8_t response[sizeof(struct ccd_info_response_packet)];
2931*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
2932*4f2df630SAndroid Build Coastguard Worker struct ccd_info_response ccd_info;
2933*4f2df630SAndroid Build Coastguard Worker uint32_t ccd_info_version;
2934*4f2df630SAndroid Build Coastguard Worker int allow_unverified_ro_cap;
2935*4f2df630SAndroid Build Coastguard Worker int rv;
2936*4f2df630SAndroid Build Coastguard Worker
2937*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_CCD, &cmd, sizeof(cmd),
2938*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
2939*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
2940*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: rv %d, response %d\n", rv,
2941*4f2df630SAndroid Build Coastguard Worker response_size ? response[0] : 0);
2942*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2943*4f2df630SAndroid Build Coastguard Worker }
2944*4f2df630SAndroid Build Coastguard Worker ccd_info_version = validate_into_ccd_info_response(
2945*4f2df630SAndroid Build Coastguard Worker response, response_size, &ccd_info);
2946*4f2df630SAndroid Build Coastguard Worker if (ccd_info_version != 1) {
2947*4f2df630SAndroid Build Coastguard Worker /*
2948*4f2df630SAndroid Build Coastguard Worker * We also don't know what order future ccd info versions will
2949*4f2df630SAndroid Build Coastguard Worker * place the AllowUnverifiedRO capability. We need to ensure
2950*4f2df630SAndroid Build Coastguard Worker * that the array lookup below is still correct for future
2951*4f2df630SAndroid Build Coastguard Worker * version if/when they become available
2952*4f2df630SAndroid Build Coastguard Worker */
2953*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
2954*4f2df630SAndroid Build Coastguard Worker "Error: CCD info version incorrect (%d).\n"
2955*4f2df630SAndroid Build Coastguard Worker "Cr50 does not support this operation.\n",
2956*4f2df630SAndroid Build Coastguard Worker ccd_info_version);
2957*4f2df630SAndroid Build Coastguard Worker exit(update_error);
2958*4f2df630SAndroid Build Coastguard Worker }
2959*4f2df630SAndroid Build Coastguard Worker /*
2960*4f2df630SAndroid Build Coastguard Worker * Pull out the AllowUnverifiedRo cap from the list.
2961*4f2df630SAndroid Build Coastguard Worker * See ti50_cap_info for full order of V1 capabilities
2962*4f2df630SAndroid Build Coastguard Worker */
2963*4f2df630SAndroid Build Coastguard Worker allow_unverified_ro_cap = (ccd_info.ccd_caps_current[1] >> 10) &
2964*4f2df630SAndroid Build Coastguard Worker CCD_CAP_BITMASK;
2965*4f2df630SAndroid Build Coastguard Worker
2966*4f2df630SAndroid Build Coastguard Worker return allow_unverified_ro_cap == CCD_CAP_STATE_ALWAYS;
2967*4f2df630SAndroid Build Coastguard Worker }
2968*4f2df630SAndroid Build Coastguard Worker
process_wp(struct transfer_descriptor * td,enum wp_options wp)2969*4f2df630SAndroid Build Coastguard Worker static enum exit_values process_wp(struct transfer_descriptor *td,
2970*4f2df630SAndroid Build Coastguard Worker enum wp_options wp)
2971*4f2df630SAndroid Build Coastguard Worker {
2972*4f2df630SAndroid Build Coastguard Worker size_t response_size;
2973*4f2df630SAndroid Build Coastguard Worker uint8_t response;
2974*4f2df630SAndroid Build Coastguard Worker int rv = 0;
2975*4f2df630SAndroid Build Coastguard Worker uint8_t command = wp;
2976*4f2df630SAndroid Build Coastguard Worker
2977*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
2978*4f2df630SAndroid Build Coastguard Worker
2979*4f2df630SAndroid Build Coastguard Worker /*
2980*4f2df630SAndroid Build Coastguard Worker * Ti50 supports enable, disable, and follow, but cr50 doesn't and will
2981*4f2df630SAndroid Build Coastguard Worker * return an error from the chip. gsctool supports the superset.
2982*4f2df630SAndroid Build Coastguard Worker */
2983*4f2df630SAndroid Build Coastguard Worker switch (wp) {
2984*4f2df630SAndroid Build Coastguard Worker case WP_DISABLE:
2985*4f2df630SAndroid Build Coastguard Worker case WP_FOLLOW:
2986*4f2df630SAndroid Build Coastguard Worker /* Ensure that AllowUnverifiedRo is true then fallthrough */
2987*4f2df630SAndroid Build Coastguard Worker if (!is_unverified_ro_allowed(td)) {
2988*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
2989*4f2df630SAndroid Build Coastguard Worker "Error: Must set AllowUnverifiedRo cap to "
2990*4f2df630SAndroid Build Coastguard Worker "always first.\n"
2991*4f2df630SAndroid Build Coastguard Worker "Otherwise changes to AP RO may cause system "
2992*4f2df630SAndroid Build Coastguard Worker "to no longer boot.\n"
2993*4f2df630SAndroid Build Coastguard Worker "Use `gsctool -I AllowUnverifiedRo:always`\n");
2994*4f2df630SAndroid Build Coastguard Worker return update_error;
2995*4f2df630SAndroid Build Coastguard Worker }
2996*4f2df630SAndroid Build Coastguard Worker case WP_ENABLE:
2997*4f2df630SAndroid Build Coastguard Worker printf("Setting WP\n");
2998*4f2df630SAndroid Build Coastguard Worker /* Enabling write protect doesn't require any special checks */
2999*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_WP, &command,
3000*4f2df630SAndroid Build Coastguard Worker sizeof(command), &response,
3001*4f2df630SAndroid Build Coastguard Worker &response_size);
3002*4f2df630SAndroid Build Coastguard Worker break;
3003*4f2df630SAndroid Build Coastguard Worker default:
3004*4f2df630SAndroid Build Coastguard Worker /* Just check the wp status without a parameter */
3005*4f2df630SAndroid Build Coastguard Worker printf("Getting WP\n");
3006*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_WP, NULL, 0, &response,
3007*4f2df630SAndroid Build Coastguard Worker &response_size);
3008*4f2df630SAndroid Build Coastguard Worker }
3009*4f2df630SAndroid Build Coastguard Worker
3010*4f2df630SAndroid Build Coastguard Worker /*
3011*4f2df630SAndroid Build Coastguard Worker * If we tried to disable and we got in progress, then prompt the
3012*4f2df630SAndroid Build Coastguard Worker * user for power button pushes
3013*4f2df630SAndroid Build Coastguard Worker */
3014*4f2df630SAndroid Build Coastguard Worker if (wp == WP_DISABLE && rv == VENDOR_RC_IN_PROGRESS) {
3015*4f2df630SAndroid Build Coastguard Worker /* Progress physical button request then get the wp again */
3016*4f2df630SAndroid Build Coastguard Worker poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_WP_DISABLE);
3017*4f2df630SAndroid Build Coastguard Worker /* Reset expected response size and get WP status again */
3018*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3019*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_WP, NULL, 0, &response,
3020*4f2df630SAndroid Build Coastguard Worker &response_size);
3021*4f2df630SAndroid Build Coastguard Worker }
3022*4f2df630SAndroid Build Coastguard Worker /*
3023*4f2df630SAndroid Build Coastguard Worker * Give user a more detailed error for not allowed. That means CCD
3024*4f2df630SAndroid Build Coastguard Worker * must be open before we can process the command
3025*4f2df630SAndroid Build Coastguard Worker */
3026*4f2df630SAndroid Build Coastguard Worker if (rv == VENDOR_RC_NOT_ALLOWED) {
3027*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: OverrideWP must be enabled first.\n"
3028*4f2df630SAndroid Build Coastguard Worker "Use `gsctool -I OverrideWP:always`\n");
3029*4f2df630SAndroid Build Coastguard Worker return update_error;
3030*4f2df630SAndroid Build Coastguard Worker }
3031*4f2df630SAndroid Build Coastguard Worker
3032*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3033*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d %sting write protect\n", rv,
3034*4f2df630SAndroid Build Coastguard Worker (wp == WP_ENABLE) ? "set" : "get");
3035*4f2df630SAndroid Build Coastguard Worker if (wp == WP_ENABLE) {
3036*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3037*4f2df630SAndroid Build Coastguard Worker "Early Cr50 versions do not support setting WP"
3038*4f2df630SAndroid Build Coastguard Worker "\n");
3039*4f2df630SAndroid Build Coastguard Worker }
3040*4f2df630SAndroid Build Coastguard Worker return update_error;
3041*4f2df630SAndroid Build Coastguard Worker }
3042*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(response)) {
3043*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3044*4f2df630SAndroid Build Coastguard Worker "Unexpected response size %zd while getting "
3045*4f2df630SAndroid Build Coastguard Worker "write protect\n",
3046*4f2df630SAndroid Build Coastguard Worker response_size);
3047*4f2df630SAndroid Build Coastguard Worker return update_error;
3048*4f2df630SAndroid Build Coastguard Worker }
3049*4f2df630SAndroid Build Coastguard Worker
3050*4f2df630SAndroid Build Coastguard Worker printf("WP: %08x\n", response);
3051*4f2df630SAndroid Build Coastguard Worker printf("Flash WP: %s%s%s\n",
3052*4f2df630SAndroid Build Coastguard Worker response & WPV_FWMP_FORCE_WP_EN ? "fwmp " : "",
3053*4f2df630SAndroid Build Coastguard Worker response & WPV_FORCE ? "forced " : "",
3054*4f2df630SAndroid Build Coastguard Worker response & WPV_ENABLE ? "enabled" : "disabled");
3055*4f2df630SAndroid Build Coastguard Worker printf(" at boot: %s\n",
3056*4f2df630SAndroid Build Coastguard Worker response & WPV_FWMP_FORCE_WP_EN ? "fwmp enabled" :
3057*4f2df630SAndroid Build Coastguard Worker !(response & WPV_ATBOOT_SET) ? "follow_batt_pres" :
3058*4f2df630SAndroid Build Coastguard Worker response & WPV_ATBOOT_ENABLE ? "forced enabled" :
3059*4f2df630SAndroid Build Coastguard Worker "forced disabled");
3060*4f2df630SAndroid Build Coastguard Worker return noop;
3061*4f2df630SAndroid Build Coastguard Worker }
3062*4f2df630SAndroid Build Coastguard Worker
process_get_chassis_open(struct transfer_descriptor * td)3063*4f2df630SAndroid Build Coastguard Worker static enum exit_values process_get_chassis_open(struct transfer_descriptor *td)
3064*4f2df630SAndroid Build Coastguard Worker {
3065*4f2df630SAndroid Build Coastguard Worker struct chassis_open_repsonse {
3066*4f2df630SAndroid Build Coastguard Worker uint8_t version;
3067*4f2df630SAndroid Build Coastguard Worker uint8_t chassis_open;
3068*4f2df630SAndroid Build Coastguard Worker } response;
3069*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3070*4f2df630SAndroid Build Coastguard Worker int rv;
3071*4f2df630SAndroid Build Coastguard Worker
3072*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3073*4f2df630SAndroid Build Coastguard Worker
3074*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_CHASSIS_OPEN, NULL, 0,
3075*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
3076*4f2df630SAndroid Build Coastguard Worker
3077*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3078*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d getting chassis open\n", rv);
3079*4f2df630SAndroid Build Coastguard Worker return update_error;
3080*4f2df630SAndroid Build Coastguard Worker }
3081*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(response)) {
3082*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3083*4f2df630SAndroid Build Coastguard Worker "Unexpected response size %zd while getting "
3084*4f2df630SAndroid Build Coastguard Worker "chassis open\n",
3085*4f2df630SAndroid Build Coastguard Worker response_size);
3086*4f2df630SAndroid Build Coastguard Worker return update_error;
3087*4f2df630SAndroid Build Coastguard Worker }
3088*4f2df630SAndroid Build Coastguard Worker if (response.version != 1) {
3089*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3090*4f2df630SAndroid Build Coastguard Worker "Unexpected response version %d while getting "
3091*4f2df630SAndroid Build Coastguard Worker "chassis open\n",
3092*4f2df630SAndroid Build Coastguard Worker response.version);
3093*4f2df630SAndroid Build Coastguard Worker return update_error;
3094*4f2df630SAndroid Build Coastguard Worker }
3095*4f2df630SAndroid Build Coastguard Worker
3096*4f2df630SAndroid Build Coastguard Worker printf("Chassis Open: %s\n",
3097*4f2df630SAndroid Build Coastguard Worker response.chassis_open & 1 ? "true" : "false");
3098*4f2df630SAndroid Build Coastguard Worker return noop;
3099*4f2df630SAndroid Build Coastguard Worker }
3100*4f2df630SAndroid Build Coastguard Worker
process_get_dev_ids(struct transfer_descriptor * td,bool show_machine_output)3101*4f2df630SAndroid Build Coastguard Worker static enum exit_values process_get_dev_ids(struct transfer_descriptor *td,
3102*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
3103*4f2df630SAndroid Build Coastguard Worker {
3104*4f2df630SAndroid Build Coastguard Worker struct sys_info_repsonse {
3105*4f2df630SAndroid Build Coastguard Worker uint32_t ro_keyid;
3106*4f2df630SAndroid Build Coastguard Worker uint32_t rw_keyid;
3107*4f2df630SAndroid Build Coastguard Worker uint32_t dev_id0;
3108*4f2df630SAndroid Build Coastguard Worker uint32_t dev_id1;
3109*4f2df630SAndroid Build Coastguard Worker } response;
3110*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3111*4f2df630SAndroid Build Coastguard Worker int rv;
3112*4f2df630SAndroid Build Coastguard Worker
3113*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3114*4f2df630SAndroid Build Coastguard Worker
3115*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SYSINFO, NULL, 0, &response,
3116*4f2df630SAndroid Build Coastguard Worker &response_size);
3117*4f2df630SAndroid Build Coastguard Worker
3118*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3119*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d getting device ids\n", rv);
3120*4f2df630SAndroid Build Coastguard Worker return update_error;
3121*4f2df630SAndroid Build Coastguard Worker }
3122*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(response)) {
3123*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3124*4f2df630SAndroid Build Coastguard Worker "Unexpected response size %zd while getting "
3125*4f2df630SAndroid Build Coastguard Worker "device ids\n",
3126*4f2df630SAndroid Build Coastguard Worker response_size);
3127*4f2df630SAndroid Build Coastguard Worker return update_error;
3128*4f2df630SAndroid Build Coastguard Worker }
3129*4f2df630SAndroid Build Coastguard Worker
3130*4f2df630SAndroid Build Coastguard Worker /* Convert from BE transimision format */
3131*4f2df630SAndroid Build Coastguard Worker response.dev_id0 = be32toh(response.dev_id0);
3132*4f2df630SAndroid Build Coastguard Worker response.dev_id1 = be32toh(response.dev_id1);
3133*4f2df630SAndroid Build Coastguard Worker
3134*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
3135*4f2df630SAndroid Build Coastguard Worker print_machine_output("DEV_ID0", "%08x", response.dev_id0);
3136*4f2df630SAndroid Build Coastguard Worker print_machine_output("DEV_ID1", "%08x", response.dev_id1);
3137*4f2df630SAndroid Build Coastguard Worker } else {
3138*4f2df630SAndroid Build Coastguard Worker printf("DEVID: 0x%08x 0x%08x\n", response.dev_id0,
3139*4f2df630SAndroid Build Coastguard Worker response.dev_id1);
3140*4f2df630SAndroid Build Coastguard Worker }
3141*4f2df630SAndroid Build Coastguard Worker return noop;
3142*4f2df630SAndroid Build Coastguard Worker }
3143*4f2df630SAndroid Build Coastguard Worker
process_get_aprov_reset_counts(struct transfer_descriptor * td)3144*4f2df630SAndroid Build Coastguard Worker static enum exit_values process_get_aprov_reset_counts(
3145*4f2df630SAndroid Build Coastguard Worker struct transfer_descriptor *td)
3146*4f2df630SAndroid Build Coastguard Worker {
3147*4f2df630SAndroid Build Coastguard Worker /*
3148*4f2df630SAndroid Build Coastguard Worker * We shouldn't need a version for this command since the entire
3149*4f2df630SAndroid Build Coastguard Worker * command should be removed after feature launch. However, if we
3150*4f2df630SAndroid Build Coastguard Worker * did need a version, the upper 7 bits of allow_unverified_ro are
3151*4f2df630SAndroid Build Coastguard Worker * unused.
3152*4f2df630SAndroid Build Coastguard Worker */
3153*4f2df630SAndroid Build Coastguard Worker struct aprov_reset_counts {
3154*4f2df630SAndroid Build Coastguard Worker uint8_t allow_unverified_ro;
3155*4f2df630SAndroid Build Coastguard Worker uint8_t settings_change;
3156*4f2df630SAndroid Build Coastguard Worker uint8_t external_wp;
3157*4f2df630SAndroid Build Coastguard Worker uint8_t internal_wp;
3158*4f2df630SAndroid Build Coastguard Worker } response;
3159*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3160*4f2df630SAndroid Build Coastguard Worker int rv;
3161*4f2df630SAndroid Build Coastguard Worker int32_t allow_unverified_sign = 1;
3162*4f2df630SAndroid Build Coastguard Worker
3163*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3164*4f2df630SAndroid Build Coastguard Worker
3165*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_AP_RO_RESET_COUNTS, NULL, 0,
3166*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
3167*4f2df630SAndroid Build Coastguard Worker
3168*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3169*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d getting reset counts\n", rv);
3170*4f2df630SAndroid Build Coastguard Worker return update_error;
3171*4f2df630SAndroid Build Coastguard Worker }
3172*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(response)) {
3173*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3174*4f2df630SAndroid Build Coastguard Worker "Unexpected response size %zd while getting "
3175*4f2df630SAndroid Build Coastguard Worker "reset counts\n",
3176*4f2df630SAndroid Build Coastguard Worker response_size);
3177*4f2df630SAndroid Build Coastguard Worker return update_error;
3178*4f2df630SAndroid Build Coastguard Worker }
3179*4f2df630SAndroid Build Coastguard Worker
3180*4f2df630SAndroid Build Coastguard Worker /* Change all of the values to negative if unverified RO is allowed. */
3181*4f2df630SAndroid Build Coastguard Worker if (response.allow_unverified_ro != 0)
3182*4f2df630SAndroid Build Coastguard Worker allow_unverified_sign = -1;
3183*4f2df630SAndroid Build Coastguard Worker
3184*4f2df630SAndroid Build Coastguard Worker const uint32_t combined = response.settings_change +
3185*4f2df630SAndroid Build Coastguard Worker (response.external_wp << 8) +
3186*4f2df630SAndroid Build Coastguard Worker (response.internal_wp << 16);
3187*4f2df630SAndroid Build Coastguard Worker
3188*4f2df630SAndroid Build Coastguard Worker /*
3189*4f2df630SAndroid Build Coastguard Worker * The `cr50-metrics.conf` file depends on these string names. Do
3190*4f2df630SAndroid Build Coastguard Worker * not change without updated that file.
3191*4f2df630SAndroid Build Coastguard Worker */
3192*4f2df630SAndroid Build Coastguard Worker print_machine_output("COMBINED", "0x%08x",
3193*4f2df630SAndroid Build Coastguard Worker allow_unverified_sign * combined);
3194*4f2df630SAndroid Build Coastguard Worker print_machine_output("SETTINGS_CHANGE", "0x%08x",
3195*4f2df630SAndroid Build Coastguard Worker allow_unverified_sign * response.settings_change);
3196*4f2df630SAndroid Build Coastguard Worker print_machine_output("EXTERNAL_WP", "0x%08x",
3197*4f2df630SAndroid Build Coastguard Worker allow_unverified_sign * response.external_wp);
3198*4f2df630SAndroid Build Coastguard Worker print_machine_output("INTERNAL_WP", "0x%08x",
3199*4f2df630SAndroid Build Coastguard Worker allow_unverified_sign * response.internal_wp);
3200*4f2df630SAndroid Build Coastguard Worker return noop;
3201*4f2df630SAndroid Build Coastguard Worker }
3202*4f2df630SAndroid Build Coastguard Worker
process_get_apro_hash(struct transfer_descriptor * td)3203*4f2df630SAndroid Build Coastguard Worker static int process_get_apro_hash(struct transfer_descriptor *td)
3204*4f2df630SAndroid Build Coastguard Worker {
3205*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3206*4f2df630SAndroid Build Coastguard Worker uint8_t response[SHA256_DIGEST_SIZE];
3207*4f2df630SAndroid Build Coastguard Worker const char *const desc = "getting apro hash";
3208*4f2df630SAndroid Build Coastguard Worker int rv = 0;
3209*4f2df630SAndroid Build Coastguard Worker int i;
3210*4f2df630SAndroid Build Coastguard Worker
3211*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3212*4f2df630SAndroid Build Coastguard Worker
3213*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_AP_RO_HASH, NULL, 0,
3214*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
3215*4f2df630SAndroid Build Coastguard Worker
3216*4f2df630SAndroid Build Coastguard Worker if (response_size == 1) {
3217*4f2df630SAndroid Build Coastguard Worker printf("get hash rc: %d ", response[0]);
3218*4f2df630SAndroid Build Coastguard Worker switch (response[0]) {
3219*4f2df630SAndroid Build Coastguard Worker case ARCVE_NOT_PROGRAMMED:
3220*4f2df630SAndroid Build Coastguard Worker printf("AP RO hash unprogrammed\n");
3221*4f2df630SAndroid Build Coastguard Worker return 0;
3222*4f2df630SAndroid Build Coastguard Worker case ARCVE_FLASH_READ_FAILED:
3223*4f2df630SAndroid Build Coastguard Worker printf("flash read failed\n");
3224*4f2df630SAndroid Build Coastguard Worker return 0;
3225*4f2df630SAndroid Build Coastguard Worker case ARCVE_BOARD_ID_BLOCKED:
3226*4f2df630SAndroid Build Coastguard Worker printf("board id blocked\n");
3227*4f2df630SAndroid Build Coastguard Worker return 0;
3228*4f2df630SAndroid Build Coastguard Worker default:
3229*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "unexpected error\n");
3230*4f2df630SAndroid Build Coastguard Worker return update_error;
3231*4f2df630SAndroid Build Coastguard Worker }
3232*4f2df630SAndroid Build Coastguard Worker } else if (rv != VENDOR_RC_SUCCESS) {
3233*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d %s\n", rv, desc);
3234*4f2df630SAndroid Build Coastguard Worker return update_error;
3235*4f2df630SAndroid Build Coastguard Worker } else if (response_size != SHA256_DIGEST_SIZE) {
3236*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error in the size of response, %zu.\n",
3237*4f2df630SAndroid Build Coastguard Worker response_size);
3238*4f2df630SAndroid Build Coastguard Worker return update_error;
3239*4f2df630SAndroid Build Coastguard Worker }
3240*4f2df630SAndroid Build Coastguard Worker printf("digest: ");
3241*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < SHA256_DIGEST_SIZE; i++)
3242*4f2df630SAndroid Build Coastguard Worker printf("%x", response[i]);
3243*4f2df630SAndroid Build Coastguard Worker printf("\n");
3244*4f2df630SAndroid Build Coastguard Worker return 0;
3245*4f2df630SAndroid Build Coastguard Worker }
3246*4f2df630SAndroid Build Coastguard Worker
process_get_apro_boot_status(struct transfer_descriptor * td)3247*4f2df630SAndroid Build Coastguard Worker static int process_get_apro_boot_status(struct transfer_descriptor *td)
3248*4f2df630SAndroid Build Coastguard Worker {
3249*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3250*4f2df630SAndroid Build Coastguard Worker uint8_t response;
3251*4f2df630SAndroid Build Coastguard Worker const char *const desc = "getting apro status";
3252*4f2df630SAndroid Build Coastguard Worker int rv = 0;
3253*4f2df630SAndroid Build Coastguard Worker
3254*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3255*4f2df630SAndroid Build Coastguard Worker
3256*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_AP_RO_STATUS, NULL, 0,
3257*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
3258*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3259*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d %s\n", rv, desc);
3260*4f2df630SAndroid Build Coastguard Worker return update_error;
3261*4f2df630SAndroid Build Coastguard Worker }
3262*4f2df630SAndroid Build Coastguard Worker if (response_size != 1) {
3263*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected response size %zd while %s\n",
3264*4f2df630SAndroid Build Coastguard Worker response_size, desc);
3265*4f2df630SAndroid Build Coastguard Worker return update_error;
3266*4f2df630SAndroid Build Coastguard Worker }
3267*4f2df630SAndroid Build Coastguard Worker
3268*4f2df630SAndroid Build Coastguard Worker /* Print the response and meaning, as in 'enum ap_ro_status'. */
3269*4f2df630SAndroid Build Coastguard Worker printf("apro result (%d) : ", response);
3270*4f2df630SAndroid Build Coastguard Worker switch (response) {
3271*4f2df630SAndroid Build Coastguard Worker case AP_RO_NOT_RUN:
3272*4f2df630SAndroid Build Coastguard Worker printf("not run\n");
3273*4f2df630SAndroid Build Coastguard Worker break;
3274*4f2df630SAndroid Build Coastguard Worker case AP_RO_PASS:
3275*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_SUCCESS:
3276*4f2df630SAndroid Build Coastguard Worker printf("pass\n");
3277*4f2df630SAndroid Build Coastguard Worker break;
3278*4f2df630SAndroid Build Coastguard Worker case AP_RO_PASS_UNVERIFIED_GBB:
3279*4f2df630SAndroid Build Coastguard Worker printf("pass - unverified gbb!\n");
3280*4f2df630SAndroid Build Coastguard Worker break;
3281*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_NON_ZERO_GBB_FLAGS:
3282*4f2df630SAndroid Build Coastguard Worker printf("pass - except non-zero gbb flags!\n");
3283*4f2df630SAndroid Build Coastguard Worker break;
3284*4f2df630SAndroid Build Coastguard Worker case AP_RO_FAIL:
3285*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_FAILED_VERIFICATION:
3286*4f2df630SAndroid Build Coastguard Worker printf("FAIL\n");
3287*4f2df630SAndroid Build Coastguard Worker break;
3288*4f2df630SAndroid Build Coastguard Worker case AP_RO_UNSUPPORTED_TRIGGERED:
3289*4f2df630SAndroid Build Coastguard Worker printf("not supported\ntriggered: yes\n");
3290*4f2df630SAndroid Build Coastguard Worker break;
3291*4f2df630SAndroid Build Coastguard Worker case AP_RO_UNSUPPORTED_UNKNOWN:
3292*4f2df630SAndroid Build Coastguard Worker printf("not supported\ntriggered: unknown\n");
3293*4f2df630SAndroid Build Coastguard Worker break;
3294*4f2df630SAndroid Build Coastguard Worker case AP_RO_UNSUPPORTED_NOT_TRIGGERED:
3295*4f2df630SAndroid Build Coastguard Worker printf("not supported\ntriggered: no\n");
3296*4f2df630SAndroid Build Coastguard Worker break;
3297*4f2df630SAndroid Build Coastguard Worker case AP_RO_IN_PROGRESS:
3298*4f2df630SAndroid Build Coastguard Worker printf("in progress.");
3299*4f2df630SAndroid Build Coastguard Worker break;
3300*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_INCONSISTENT_GSCVD:
3301*4f2df630SAndroid Build Coastguard Worker printf("inconsistent gscvd\n");
3302*4f2df630SAndroid Build Coastguard Worker break;
3303*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_INCONSISTENT_KEYBLOCK:
3304*4f2df630SAndroid Build Coastguard Worker printf("inconsistent keyblock\n");
3305*4f2df630SAndroid Build Coastguard Worker break;
3306*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_INCONSISTENT_KEY:
3307*4f2df630SAndroid Build Coastguard Worker printf("inconsistent key\n");
3308*4f2df630SAndroid Build Coastguard Worker break;
3309*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_SPI_READ:
3310*4f2df630SAndroid Build Coastguard Worker printf("spi read failure\n");
3311*4f2df630SAndroid Build Coastguard Worker break;
3312*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_UNSUPPORTED_CRYPTO_ALGORITHM:
3313*4f2df630SAndroid Build Coastguard Worker printf("unsupported crypto algo\n");
3314*4f2df630SAndroid Build Coastguard Worker break;
3315*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_VERSION_MISMATCH:
3316*4f2df630SAndroid Build Coastguard Worker printf("header version mismatch\n");
3317*4f2df630SAndroid Build Coastguard Worker break;
3318*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_OUT_OF_MEMORY:
3319*4f2df630SAndroid Build Coastguard Worker printf("out of memory\n");
3320*4f2df630SAndroid Build Coastguard Worker break;
3321*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_INTERNAL:
3322*4f2df630SAndroid Build Coastguard Worker printf("internal\n");
3323*4f2df630SAndroid Build Coastguard Worker break;
3324*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_TOO_BIG:
3325*4f2df630SAndroid Build Coastguard Worker printf("too many areas\n");
3326*4f2df630SAndroid Build Coastguard Worker break;
3327*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_MISSING_GSCVD:
3328*4f2df630SAndroid Build Coastguard Worker printf("missing gscvd\n");
3329*4f2df630SAndroid Build Coastguard Worker break;
3330*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_BOARD_ID_MISMATCH:
3331*4f2df630SAndroid Build Coastguard Worker printf("board id mismatch\n");
3332*4f2df630SAndroid Build Coastguard Worker break;
3333*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_SETTING_NOT_PROVISIONED:
3334*4f2df630SAndroid Build Coastguard Worker printf("setting not provisioned\n");
3335*4f2df630SAndroid Build Coastguard Worker break;
3336*4f2df630SAndroid Build Coastguard Worker case AP_RO_V2_WRONG_ROOT_KEY:
3337*4f2df630SAndroid Build Coastguard Worker printf("key is recognized but disallowed (e.g. preMP key)\n");
3338*4f2df630SAndroid Build Coastguard Worker break;
3339*4f2df630SAndroid Build Coastguard Worker default:
3340*4f2df630SAndroid Build Coastguard Worker printf("unknown\n");
3341*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "unknown status\n");
3342*4f2df630SAndroid Build Coastguard Worker return update_error;
3343*4f2df630SAndroid Build Coastguard Worker }
3344*4f2df630SAndroid Build Coastguard Worker
3345*4f2df630SAndroid Build Coastguard Worker return 0;
3346*4f2df630SAndroid Build Coastguard Worker }
3347*4f2df630SAndroid Build Coastguard Worker
process_arv_config_spi_addr_mode(struct transfer_descriptor * td,int arv_config_spi_addr_mode)3348*4f2df630SAndroid Build Coastguard Worker static int process_arv_config_spi_addr_mode(struct transfer_descriptor *td,
3349*4f2df630SAndroid Build Coastguard Worker int arv_config_spi_addr_mode)
3350*4f2df630SAndroid Build Coastguard Worker {
3351*4f2df630SAndroid Build Coastguard Worker enum ap_ro_config_spi_mode_e {
3352*4f2df630SAndroid Build Coastguard Worker ap_ro_spi_config_3byte = 0,
3353*4f2df630SAndroid Build Coastguard Worker ap_ro_spi_config_4byte = 1,
3354*4f2df630SAndroid Build Coastguard Worker };
3355*4f2df630SAndroid Build Coastguard Worker
3356*4f2df630SAndroid Build Coastguard Worker struct __attribute__((__packed__)) ap_ro_config_spi_mode_msg {
3357*4f2df630SAndroid Build Coastguard Worker uint8_t version;
3358*4f2df630SAndroid Build Coastguard Worker uint8_t command;
3359*4f2df630SAndroid Build Coastguard Worker uint8_t state;
3360*4f2df630SAndroid Build Coastguard Worker uint8_t mode;
3361*4f2df630SAndroid Build Coastguard Worker };
3362*4f2df630SAndroid Build Coastguard Worker
3363*4f2df630SAndroid Build Coastguard Worker struct ap_ro_config_spi_mode_msg msg = {
3364*4f2df630SAndroid Build Coastguard Worker .version = ARV_CONFIG_SETTING_CURRENT_VERSION,
3365*4f2df630SAndroid Build Coastguard Worker .command = arv_config_setting_command_spi_addressing_mode,
3366*4f2df630SAndroid Build Coastguard Worker .state = arv_config_setting_state_present,
3367*4f2df630SAndroid Build Coastguard Worker .mode = ap_ro_spi_config_4byte
3368*4f2df630SAndroid Build Coastguard Worker };
3369*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(msg);
3370*4f2df630SAndroid Build Coastguard Worker int rv = 0;
3371*4f2df630SAndroid Build Coastguard Worker
3372*4f2df630SAndroid Build Coastguard Worker switch (arv_config_spi_addr_mode) {
3373*4f2df630SAndroid Build Coastguard Worker case arv_config_spi_addr_mode_get:
3374*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_AP_RO_VERIFY_SETTING,
3375*4f2df630SAndroid Build Coastguard Worker &msg, sizeof(msg), &msg,
3376*4f2df630SAndroid Build Coastguard Worker &response_size);
3377*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3378*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3379*4f2df630SAndroid Build Coastguard Worker "Error %d getting ap ro spi addr mode\n", rv);
3380*4f2df630SAndroid Build Coastguard Worker return update_error;
3381*4f2df630SAndroid Build Coastguard Worker }
3382*4f2df630SAndroid Build Coastguard Worker
3383*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(msg)) {
3384*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3385*4f2df630SAndroid Build Coastguard Worker "Error getting ap ro spi addr mode response\n");
3386*4f2df630SAndroid Build Coastguard Worker return update_error;
3387*4f2df630SAndroid Build Coastguard Worker }
3388*4f2df630SAndroid Build Coastguard Worker
3389*4f2df630SAndroid Build Coastguard Worker if (msg.state != arv_config_setting_state_present) {
3390*4f2df630SAndroid Build Coastguard Worker switch (msg.state) {
3391*4f2df630SAndroid Build Coastguard Worker case arv_config_setting_state_not_present:
3392*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "not provisioned\n");
3393*4f2df630SAndroid Build Coastguard Worker break;
3394*4f2df630SAndroid Build Coastguard Worker case arv_config_setting_state_corrupted:
3395*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "corrupted\n");
3396*4f2df630SAndroid Build Coastguard Worker break;
3397*4f2df630SAndroid Build Coastguard Worker case arv_config_setting_state_invalid:
3398*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "invalid\n");
3399*4f2df630SAndroid Build Coastguard Worker break;
3400*4f2df630SAndroid Build Coastguard Worker default:
3401*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3402*4f2df630SAndroid Build Coastguard Worker "unexpected message response state\n");
3403*4f2df630SAndroid Build Coastguard Worker return update_error;
3404*4f2df630SAndroid Build Coastguard Worker }
3405*4f2df630SAndroid Build Coastguard Worker return 0;
3406*4f2df630SAndroid Build Coastguard Worker }
3407*4f2df630SAndroid Build Coastguard Worker
3408*4f2df630SAndroid Build Coastguard Worker switch (msg.mode) {
3409*4f2df630SAndroid Build Coastguard Worker case ap_ro_spi_config_3byte:
3410*4f2df630SAndroid Build Coastguard Worker printf("3byte\n");
3411*4f2df630SAndroid Build Coastguard Worker break;
3412*4f2df630SAndroid Build Coastguard Worker case ap_ro_spi_config_4byte:
3413*4f2df630SAndroid Build Coastguard Worker printf("4byte\n");
3414*4f2df630SAndroid Build Coastguard Worker break;
3415*4f2df630SAndroid Build Coastguard Worker default:
3416*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "unknown spi mode\n");
3417*4f2df630SAndroid Build Coastguard Worker return update_error;
3418*4f2df630SAndroid Build Coastguard Worker }
3419*4f2df630SAndroid Build Coastguard Worker
3420*4f2df630SAndroid Build Coastguard Worker break;
3421*4f2df630SAndroid Build Coastguard Worker case arv_config_spi_addr_mode_set_3byte:
3422*4f2df630SAndroid Build Coastguard Worker msg.mode = ap_ro_spi_config_3byte;
3423*4f2df630SAndroid Build Coastguard Worker /* Fallthrough */
3424*4f2df630SAndroid Build Coastguard Worker case arv_config_spi_addr_mode_set_4byte:
3425*4f2df630SAndroid Build Coastguard Worker /* The default is 4byte addressing */
3426*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SET_AP_RO_VERIFY_SETTING,
3427*4f2df630SAndroid Build Coastguard Worker &msg, sizeof(msg), &msg,
3428*4f2df630SAndroid Build Coastguard Worker &response_size);
3429*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3430*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3431*4f2df630SAndroid Build Coastguard Worker "Error %d setting ap ro spi addr mode\n", rv);
3432*4f2df630SAndroid Build Coastguard Worker return update_error;
3433*4f2df630SAndroid Build Coastguard Worker }
3434*4f2df630SAndroid Build Coastguard Worker break;
3435*4f2df630SAndroid Build Coastguard Worker default:
3436*4f2df630SAndroid Build Coastguard Worker return update_error;
3437*4f2df630SAndroid Build Coastguard Worker }
3438*4f2df630SAndroid Build Coastguard Worker
3439*4f2df630SAndroid Build Coastguard Worker return 0;
3440*4f2df630SAndroid Build Coastguard Worker }
3441*4f2df630SAndroid Build Coastguard Worker
3442*4f2df630SAndroid Build Coastguard Worker /*
3443*4f2df630SAndroid Build Coastguard Worker * Reads an ascii hex byte in the following forms:
3444*4f2df630SAndroid Build Coastguard Worker * - 0x01
3445*4f2df630SAndroid Build Coastguard Worker * - 0x1
3446*4f2df630SAndroid Build Coastguard Worker * - 01
3447*4f2df630SAndroid Build Coastguard Worker * - 0
3448*4f2df630SAndroid Build Coastguard Worker *
3449*4f2df630SAndroid Build Coastguard Worker * 1 is returned on success, 0 on failure.
3450*4f2df630SAndroid Build Coastguard Worker */
read_hex_byte_string(char * s,uint8_t * byte)3451*4f2df630SAndroid Build Coastguard Worker static int read_hex_byte_string(char *s, uint8_t *byte)
3452*4f2df630SAndroid Build Coastguard Worker {
3453*4f2df630SAndroid Build Coastguard Worker uint8_t b = 0;
3454*4f2df630SAndroid Build Coastguard Worker
3455*4f2df630SAndroid Build Coastguard Worker if (!strncmp(s, "0x", 2))
3456*4f2df630SAndroid Build Coastguard Worker s += 2;
3457*4f2df630SAndroid Build Coastguard Worker
3458*4f2df630SAndroid Build Coastguard Worker if (strlen(s) == 0)
3459*4f2df630SAndroid Build Coastguard Worker return 0;
3460*4f2df630SAndroid Build Coastguard Worker
3461*4f2df630SAndroid Build Coastguard Worker for (const char *end = s + 2; s < end; ++s) {
3462*4f2df630SAndroid Build Coastguard Worker if (*s >= '0' && *s <= '9')
3463*4f2df630SAndroid Build Coastguard Worker b = b * 16 + *s - '0';
3464*4f2df630SAndroid Build Coastguard Worker else if (*s >= 'A' && *s <= 'F')
3465*4f2df630SAndroid Build Coastguard Worker b = b * 16 + 10 + *s - 'A';
3466*4f2df630SAndroid Build Coastguard Worker else if (*s >= 'a' && *s <= 'f')
3467*4f2df630SAndroid Build Coastguard Worker b = b * 16 + 10 + *s - 'a';
3468*4f2df630SAndroid Build Coastguard Worker else if (*s == '\0')
3469*4f2df630SAndroid Build Coastguard Worker /* Single nibble, do nothing instead of `break`
3470*4f2df630SAndroid Build Coastguard Worker * to keep checkpatch happy
3471*4f2df630SAndroid Build Coastguard Worker */
3472*4f2df630SAndroid Build Coastguard Worker ;
3473*4f2df630SAndroid Build Coastguard Worker else
3474*4f2df630SAndroid Build Coastguard Worker /* Invalid nibble */
3475*4f2df630SAndroid Build Coastguard Worker return 0;
3476*4f2df630SAndroid Build Coastguard Worker }
3477*4f2df630SAndroid Build Coastguard Worker *byte = b;
3478*4f2df630SAndroid Build Coastguard Worker return 1;
3479*4f2df630SAndroid Build Coastguard Worker }
3480*4f2df630SAndroid Build Coastguard Worker
parse_wpsrs(const char * opt,struct arv_config_wpds * wpds)3481*4f2df630SAndroid Build Coastguard Worker static int parse_wpsrs(const char *opt, struct arv_config_wpds *wpds)
3482*4f2df630SAndroid Build Coastguard Worker {
3483*4f2df630SAndroid Build Coastguard Worker size_t len = strlen(opt);
3484*4f2df630SAndroid Build Coastguard Worker char *ptr, *p, *delim = " ";
3485*4f2df630SAndroid Build Coastguard Worker uint8_t b;
3486*4f2df630SAndroid Build Coastguard Worker int rv = 0;
3487*4f2df630SAndroid Build Coastguard Worker struct arv_config_wpd *wpd;
3488*4f2df630SAndroid Build Coastguard Worker
3489*4f2df630SAndroid Build Coastguard Worker ptr = malloc(len + 1);
3490*4f2df630SAndroid Build Coastguard Worker strcpy(ptr, opt);
3491*4f2df630SAndroid Build Coastguard Worker p = strtok(ptr, delim);
3492*4f2df630SAndroid Build Coastguard Worker
3493*4f2df630SAndroid Build Coastguard Worker while (p != NULL) {
3494*4f2df630SAndroid Build Coastguard Worker if (read_hex_byte_string(p, &b)) {
3495*4f2df630SAndroid Build Coastguard Worker wpd = &wpds->data[rv / 2];
3496*4f2df630SAndroid Build Coastguard Worker if (rv % 2 == 0) {
3497*4f2df630SAndroid Build Coastguard Worker wpd->expected_value = b;
3498*4f2df630SAndroid Build Coastguard Worker } else {
3499*4f2df630SAndroid Build Coastguard Worker wpd->mask = b;
3500*4f2df630SAndroid Build Coastguard Worker wpd->state = arv_config_setting_state_present;
3501*4f2df630SAndroid Build Coastguard Worker }
3502*4f2df630SAndroid Build Coastguard Worker rv++;
3503*4f2df630SAndroid Build Coastguard Worker } else {
3504*4f2df630SAndroid Build Coastguard Worker break;
3505*4f2df630SAndroid Build Coastguard Worker }
3506*4f2df630SAndroid Build Coastguard Worker p = strtok(NULL, delim);
3507*4f2df630SAndroid Build Coastguard Worker }
3508*4f2df630SAndroid Build Coastguard Worker free(ptr);
3509*4f2df630SAndroid Build Coastguard Worker
3510*4f2df630SAndroid Build Coastguard Worker return rv;
3511*4f2df630SAndroid Build Coastguard Worker }
3512*4f2df630SAndroid Build Coastguard Worker
print_wpd(size_t i,struct arv_config_wpd * wpd)3513*4f2df630SAndroid Build Coastguard Worker static void print_wpd(size_t i, struct arv_config_wpd *wpd)
3514*4f2df630SAndroid Build Coastguard Worker {
3515*4f2df630SAndroid Build Coastguard Worker if (wpd->state == arv_config_setting_state_not_present) {
3516*4f2df630SAndroid Build Coastguard Worker printf("not provisioned");
3517*4f2df630SAndroid Build Coastguard Worker return;
3518*4f2df630SAndroid Build Coastguard Worker } else if (wpd->state == arv_config_setting_state_corrupted) {
3519*4f2df630SAndroid Build Coastguard Worker printf("corrupted");
3520*4f2df630SAndroid Build Coastguard Worker return;
3521*4f2df630SAndroid Build Coastguard Worker } else if (wpd->state == arv_config_setting_state_invalid) {
3522*4f2df630SAndroid Build Coastguard Worker printf("invalid");
3523*4f2df630SAndroid Build Coastguard Worker return;
3524*4f2df630SAndroid Build Coastguard Worker }
3525*4f2df630SAndroid Build Coastguard Worker
3526*4f2df630SAndroid Build Coastguard Worker printf("%zu: %02x & %02x", i, wpd->expected_value, wpd->mask);
3527*4f2df630SAndroid Build Coastguard Worker }
3528*4f2df630SAndroid Build Coastguard Worker
process_arv_config_wpds(struct transfer_descriptor * td,enum arv_config_wpsr_choice_e choice,struct arv_config_wpds * wpds)3529*4f2df630SAndroid Build Coastguard Worker static int process_arv_config_wpds(struct transfer_descriptor *td,
3530*4f2df630SAndroid Build Coastguard Worker enum arv_config_wpsr_choice_e choice,
3531*4f2df630SAndroid Build Coastguard Worker struct arv_config_wpds *wpds)
3532*4f2df630SAndroid Build Coastguard Worker {
3533*4f2df630SAndroid Build Coastguard Worker struct __attribute__((__packed__)) arv_config_wpds_message {
3534*4f2df630SAndroid Build Coastguard Worker uint8_t version;
3535*4f2df630SAndroid Build Coastguard Worker /* See `arv_config_setting_command_e` */
3536*4f2df630SAndroid Build Coastguard Worker uint8_t command;
3537*4f2df630SAndroid Build Coastguard Worker struct arv_config_wpds wpds;
3538*4f2df630SAndroid Build Coastguard Worker };
3539*4f2df630SAndroid Build Coastguard Worker int rv = 0;
3540*4f2df630SAndroid Build Coastguard Worker
3541*4f2df630SAndroid Build Coastguard Worker struct arv_config_wpds_message msg = {
3542*4f2df630SAndroid Build Coastguard Worker .version = ARV_CONFIG_SETTING_CURRENT_VERSION,
3543*4f2df630SAndroid Build Coastguard Worker .command = arv_config_setting_command_write_protect_descriptors,
3544*4f2df630SAndroid Build Coastguard Worker };
3545*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(msg);
3546*4f2df630SAndroid Build Coastguard Worker
3547*4f2df630SAndroid Build Coastguard Worker if (choice == arv_config_wpsr_choice_get) {
3548*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_AP_RO_VERIFY_SETTING,
3549*4f2df630SAndroid Build Coastguard Worker &msg, sizeof(msg), &msg,
3550*4f2df630SAndroid Build Coastguard Worker &response_size);
3551*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3552*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3553*4f2df630SAndroid Build Coastguard Worker "Error %d getting ap ro write protect descriptors\n",
3554*4f2df630SAndroid Build Coastguard Worker rv);
3555*4f2df630SAndroid Build Coastguard Worker return update_error;
3556*4f2df630SAndroid Build Coastguard Worker }
3557*4f2df630SAndroid Build Coastguard Worker
3558*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(msg)) {
3559*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3560*4f2df630SAndroid Build Coastguard Worker "Error getting ap ro write protect descriptors response\n");
3561*4f2df630SAndroid Build Coastguard Worker return update_error;
3562*4f2df630SAndroid Build Coastguard Worker }
3563*4f2df630SAndroid Build Coastguard Worker
3564*4f2df630SAndroid Build Coastguard Worker if (msg.wpds.data[0].state ==
3565*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_present) {
3566*4f2df630SAndroid Build Coastguard Worker printf("expected values: ");
3567*4f2df630SAndroid Build Coastguard Worker }
3568*4f2df630SAndroid Build Coastguard Worker print_wpd(1, &msg.wpds.data[0]);
3569*4f2df630SAndroid Build Coastguard Worker if (msg.wpds.data[1].state !=
3570*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_not_present) {
3571*4f2df630SAndroid Build Coastguard Worker printf(", ");
3572*4f2df630SAndroid Build Coastguard Worker print_wpd(2, &msg.wpds.data[1]);
3573*4f2df630SAndroid Build Coastguard Worker }
3574*4f2df630SAndroid Build Coastguard Worker if (msg.wpds.data[2].state !=
3575*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_not_present) {
3576*4f2df630SAndroid Build Coastguard Worker printf(", ");
3577*4f2df630SAndroid Build Coastguard Worker print_wpd(3, &msg.wpds.data[2]);
3578*4f2df630SAndroid Build Coastguard Worker }
3579*4f2df630SAndroid Build Coastguard Worker
3580*4f2df630SAndroid Build Coastguard Worker printf("\n");
3581*4f2df630SAndroid Build Coastguard Worker } else if (choice == arv_config_wpsr_choice_set) {
3582*4f2df630SAndroid Build Coastguard Worker msg.wpds = *wpds;
3583*4f2df630SAndroid Build Coastguard Worker
3584*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SET_AP_RO_VERIFY_SETTING,
3585*4f2df630SAndroid Build Coastguard Worker &msg, sizeof(msg), &msg,
3586*4f2df630SAndroid Build Coastguard Worker &response_size);
3587*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3588*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3589*4f2df630SAndroid Build Coastguard Worker "Error %d setting ap ro write protect descriptors\n",
3590*4f2df630SAndroid Build Coastguard Worker rv);
3591*4f2df630SAndroid Build Coastguard Worker return update_error;
3592*4f2df630SAndroid Build Coastguard Worker }
3593*4f2df630SAndroid Build Coastguard Worker }
3594*4f2df630SAndroid Build Coastguard Worker
3595*4f2df630SAndroid Build Coastguard Worker return 0;
3596*4f2df630SAndroid Build Coastguard Worker }
3597*4f2df630SAndroid Build Coastguard Worker
process_get_boot_mode(struct transfer_descriptor * td)3598*4f2df630SAndroid Build Coastguard Worker static int process_get_boot_mode(struct transfer_descriptor *td)
3599*4f2df630SAndroid Build Coastguard Worker {
3600*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3601*4f2df630SAndroid Build Coastguard Worker uint8_t response;
3602*4f2df630SAndroid Build Coastguard Worker const char *const desc = "Getting boot mode";
3603*4f2df630SAndroid Build Coastguard Worker int rv = 0;
3604*4f2df630SAndroid Build Coastguard Worker
3605*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3606*4f2df630SAndroid Build Coastguard Worker
3607*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_BOOT_MODE, NULL, 0,
3608*4f2df630SAndroid Build Coastguard Worker &response, &response_size);
3609*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
3610*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d in %s\n", rv, desc);
3611*4f2df630SAndroid Build Coastguard Worker return update_error;
3612*4f2df630SAndroid Build Coastguard Worker }
3613*4f2df630SAndroid Build Coastguard Worker if (response_size != 1) {
3614*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected response size %zd while %s\n",
3615*4f2df630SAndroid Build Coastguard Worker response_size, desc);
3616*4f2df630SAndroid Build Coastguard Worker return update_error;
3617*4f2df630SAndroid Build Coastguard Worker }
3618*4f2df630SAndroid Build Coastguard Worker
3619*4f2df630SAndroid Build Coastguard Worker /* Print the response and meaning, as in 'enum boot_mode'. */
3620*4f2df630SAndroid Build Coastguard Worker printf("Boot mode = 0x%02x: ", response);
3621*4f2df630SAndroid Build Coastguard Worker switch (response) {
3622*4f2df630SAndroid Build Coastguard Worker case 0x00:
3623*4f2df630SAndroid Build Coastguard Worker printf("NORMAL\n");
3624*4f2df630SAndroid Build Coastguard Worker break;
3625*4f2df630SAndroid Build Coastguard Worker case 0x01:
3626*4f2df630SAndroid Build Coastguard Worker printf("NO_BOOT\n");
3627*4f2df630SAndroid Build Coastguard Worker break;
3628*4f2df630SAndroid Build Coastguard Worker default:
3629*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "unknown boot mode\n");
3630*4f2df630SAndroid Build Coastguard Worker return update_error;
3631*4f2df630SAndroid Build Coastguard Worker }
3632*4f2df630SAndroid Build Coastguard Worker
3633*4f2df630SAndroid Build Coastguard Worker return 0;
3634*4f2df630SAndroid Build Coastguard Worker }
3635*4f2df630SAndroid Build Coastguard Worker
process_bid(struct transfer_descriptor * td,enum board_id_action bid_action,struct board_id * bid,bool show_machine_output)3636*4f2df630SAndroid Build Coastguard Worker void process_bid(struct transfer_descriptor *td,
3637*4f2df630SAndroid Build Coastguard Worker enum board_id_action bid_action, struct board_id *bid,
3638*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
3639*4f2df630SAndroid Build Coastguard Worker {
3640*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3641*4f2df630SAndroid Build Coastguard Worker
3642*4f2df630SAndroid Build Coastguard Worker if (bid_action == bid_get) {
3643*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(*bid);
3644*4f2df630SAndroid Build Coastguard Worker send_vendor_command(td, VENDOR_CC_GET_BOARD_ID, bid,
3645*4f2df630SAndroid Build Coastguard Worker sizeof(*bid), bid, &response_size);
3646*4f2df630SAndroid Build Coastguard Worker
3647*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(*bid)) {
3648*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3649*4f2df630SAndroid Build Coastguard Worker "Error reading board ID: response size %zd, "
3650*4f2df630SAndroid Build Coastguard Worker "first byte %#02x\n",
3651*4f2df630SAndroid Build Coastguard Worker response_size,
3652*4f2df630SAndroid Build Coastguard Worker response_size ? *(uint8_t *)&bid : -1);
3653*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3654*4f2df630SAndroid Build Coastguard Worker }
3655*4f2df630SAndroid Build Coastguard Worker
3656*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
3657*4f2df630SAndroid Build Coastguard Worker print_machine_output("BID_TYPE", "%08x",
3658*4f2df630SAndroid Build Coastguard Worker be32toh(bid->type));
3659*4f2df630SAndroid Build Coastguard Worker print_machine_output("BID_TYPE_INV", "%08x",
3660*4f2df630SAndroid Build Coastguard Worker be32toh(bid->type_inv));
3661*4f2df630SAndroid Build Coastguard Worker print_machine_output("BID_FLAGS", "%08x",
3662*4f2df630SAndroid Build Coastguard Worker be32toh(bid->flags));
3663*4f2df630SAndroid Build Coastguard Worker
3664*4f2df630SAndroid Build Coastguard Worker for (int i = 0; i < 4; i++) {
3665*4f2df630SAndroid Build Coastguard Worker if (!isupper(((const char *)bid)[i])) {
3666*4f2df630SAndroid Build Coastguard Worker print_machine_output("BID_RLZ", "%s",
3667*4f2df630SAndroid Build Coastguard Worker "????");
3668*4f2df630SAndroid Build Coastguard Worker return;
3669*4f2df630SAndroid Build Coastguard Worker }
3670*4f2df630SAndroid Build Coastguard Worker }
3671*4f2df630SAndroid Build Coastguard Worker
3672*4f2df630SAndroid Build Coastguard Worker print_machine_output("BID_RLZ", "%c%c%c%c",
3673*4f2df630SAndroid Build Coastguard Worker ((const char *)bid)[0],
3674*4f2df630SAndroid Build Coastguard Worker ((const char *)bid)[1],
3675*4f2df630SAndroid Build Coastguard Worker ((const char *)bid)[2],
3676*4f2df630SAndroid Build Coastguard Worker ((const char *)bid)[3]);
3677*4f2df630SAndroid Build Coastguard Worker } else {
3678*4f2df630SAndroid Build Coastguard Worker printf("Board ID space: %08x:%08x:%08x\n",
3679*4f2df630SAndroid Build Coastguard Worker be32toh(bid->type), be32toh(bid->type_inv),
3680*4f2df630SAndroid Build Coastguard Worker be32toh(bid->flags));
3681*4f2df630SAndroid Build Coastguard Worker }
3682*4f2df630SAndroid Build Coastguard Worker
3683*4f2df630SAndroid Build Coastguard Worker return;
3684*4f2df630SAndroid Build Coastguard Worker }
3685*4f2df630SAndroid Build Coastguard Worker
3686*4f2df630SAndroid Build Coastguard Worker if (bid_action == bid_set) {
3687*4f2df630SAndroid Build Coastguard Worker /* Sending just two fields: type and flags. */
3688*4f2df630SAndroid Build Coastguard Worker uint32_t command_body[2];
3689*4f2df630SAndroid Build Coastguard Worker uint8_t response;
3690*4f2df630SAndroid Build Coastguard Worker
3691*4f2df630SAndroid Build Coastguard Worker command_body[0] = htobe32(bid->type);
3692*4f2df630SAndroid Build Coastguard Worker command_body[1] = htobe32(bid->flags);
3693*4f2df630SAndroid Build Coastguard Worker
3694*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(command_body);
3695*4f2df630SAndroid Build Coastguard Worker send_vendor_command(td, VENDOR_CC_SET_BOARD_ID, command_body,
3696*4f2df630SAndroid Build Coastguard Worker sizeof(command_body), command_body,
3697*4f2df630SAndroid Build Coastguard Worker &response_size);
3698*4f2df630SAndroid Build Coastguard Worker
3699*4f2df630SAndroid Build Coastguard Worker /*
3700*4f2df630SAndroid Build Coastguard Worker * Speculative assignment: the response is expected to be one
3701*4f2df630SAndroid Build Coastguard Worker * byte in size and be placed in the first byte of the buffer.
3702*4f2df630SAndroid Build Coastguard Worker */
3703*4f2df630SAndroid Build Coastguard Worker response = *((uint8_t *)command_body);
3704*4f2df630SAndroid Build Coastguard Worker
3705*4f2df630SAndroid Build Coastguard Worker if (response_size == 1) {
3706*4f2df630SAndroid Build Coastguard Worker if (!response)
3707*4f2df630SAndroid Build Coastguard Worker return; /* Success! */
3708*4f2df630SAndroid Build Coastguard Worker
3709*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d while setting board id\n",
3710*4f2df630SAndroid Build Coastguard Worker response);
3711*4f2df630SAndroid Build Coastguard Worker } else {
3712*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3713*4f2df630SAndroid Build Coastguard Worker "Unexpected response size %zd"
3714*4f2df630SAndroid Build Coastguard Worker " while setting board id\n",
3715*4f2df630SAndroid Build Coastguard Worker response_size);
3716*4f2df630SAndroid Build Coastguard Worker }
3717*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3718*4f2df630SAndroid Build Coastguard Worker }
3719*4f2df630SAndroid Build Coastguard Worker }
3720*4f2df630SAndroid Build Coastguard Worker
process_sn_bits(struct transfer_descriptor * td,uint8_t * sn_bits)3721*4f2df630SAndroid Build Coastguard Worker static void process_sn_bits(struct transfer_descriptor *td, uint8_t *sn_bits)
3722*4f2df630SAndroid Build Coastguard Worker {
3723*4f2df630SAndroid Build Coastguard Worker int rv;
3724*4f2df630SAndroid Build Coastguard Worker uint8_t response_code;
3725*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response_code);
3726*4f2df630SAndroid Build Coastguard Worker
3727*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SN_SET_HASH, sn_bits,
3728*4f2df630SAndroid Build Coastguard Worker SN_BITS_SIZE, &response_code, &response_size);
3729*4f2df630SAndroid Build Coastguard Worker
3730*4f2df630SAndroid Build Coastguard Worker if (rv) {
3731*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d while sending vendor command\n", rv);
3732*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3733*4f2df630SAndroid Build Coastguard Worker }
3734*4f2df630SAndroid Build Coastguard Worker
3735*4f2df630SAndroid Build Coastguard Worker if (response_size != 1) {
3736*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3737*4f2df630SAndroid Build Coastguard Worker "Unexpected response size while setting sn bits\n");
3738*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3739*4f2df630SAndroid Build Coastguard Worker }
3740*4f2df630SAndroid Build Coastguard Worker
3741*4f2df630SAndroid Build Coastguard Worker if (response_code != 0) {
3742*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d while setting sn bits\n",
3743*4f2df630SAndroid Build Coastguard Worker response_code);
3744*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3745*4f2df630SAndroid Build Coastguard Worker }
3746*4f2df630SAndroid Build Coastguard Worker }
3747*4f2df630SAndroid Build Coastguard Worker
process_sn_inc_rma(struct transfer_descriptor * td,uint8_t arg)3748*4f2df630SAndroid Build Coastguard Worker static void process_sn_inc_rma(struct transfer_descriptor *td, uint8_t arg)
3749*4f2df630SAndroid Build Coastguard Worker {
3750*4f2df630SAndroid Build Coastguard Worker int rv;
3751*4f2df630SAndroid Build Coastguard Worker uint8_t response_code;
3752*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response_code);
3753*4f2df630SAndroid Build Coastguard Worker
3754*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SN_INC_RMA, &arg, sizeof(arg),
3755*4f2df630SAndroid Build Coastguard Worker &response_code, &response_size);
3756*4f2df630SAndroid Build Coastguard Worker if (rv) {
3757*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d while sending vendor command\n", rv);
3758*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3759*4f2df630SAndroid Build Coastguard Worker }
3760*4f2df630SAndroid Build Coastguard Worker
3761*4f2df630SAndroid Build Coastguard Worker if (response_size != 1) {
3762*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unexpected response size while "
3763*4f2df630SAndroid Build Coastguard Worker "incrementing sn rma count\n");
3764*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3765*4f2df630SAndroid Build Coastguard Worker }
3766*4f2df630SAndroid Build Coastguard Worker
3767*4f2df630SAndroid Build Coastguard Worker if (response_code != 0) {
3768*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d while incrementing rma count\n",
3769*4f2df630SAndroid Build Coastguard Worker response_code);
3770*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3771*4f2df630SAndroid Build Coastguard Worker }
3772*4f2df630SAndroid Build Coastguard Worker }
3773*4f2df630SAndroid Build Coastguard Worker
3774*4f2df630SAndroid Build Coastguard Worker /* Get/Set the primary seed of the info1 manufacture state. */
process_endorsement_seed(struct transfer_descriptor * td,const char * endorsement_seed_str)3775*4f2df630SAndroid Build Coastguard Worker static int process_endorsement_seed(struct transfer_descriptor *td,
3776*4f2df630SAndroid Build Coastguard Worker const char *endorsement_seed_str)
3777*4f2df630SAndroid Build Coastguard Worker {
3778*4f2df630SAndroid Build Coastguard Worker uint8_t endorsement_seed[32];
3779*4f2df630SAndroid Build Coastguard Worker uint8_t response_seed[32];
3780*4f2df630SAndroid Build Coastguard Worker size_t seed_size = sizeof(endorsement_seed);
3781*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response_seed);
3782*4f2df630SAndroid Build Coastguard Worker size_t i;
3783*4f2df630SAndroid Build Coastguard Worker int rv;
3784*4f2df630SAndroid Build Coastguard Worker
3785*4f2df630SAndroid Build Coastguard Worker if (!endorsement_seed_str) {
3786*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_ENDORSEMENT_SEED, NULL,
3787*4f2df630SAndroid Build Coastguard Worker 0, response_seed, &response_size);
3788*4f2df630SAndroid Build Coastguard Worker if (rv) {
3789*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error sending vendor command %d\n",
3790*4f2df630SAndroid Build Coastguard Worker rv);
3791*4f2df630SAndroid Build Coastguard Worker return update_error;
3792*4f2df630SAndroid Build Coastguard Worker }
3793*4f2df630SAndroid Build Coastguard Worker printf("Endorsement key seed: ");
3794*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < response_size; i++)
3795*4f2df630SAndroid Build Coastguard Worker printf("%02x", response_seed[i]);
3796*4f2df630SAndroid Build Coastguard Worker printf("\n");
3797*4f2df630SAndroid Build Coastguard Worker return 0;
3798*4f2df630SAndroid Build Coastguard Worker }
3799*4f2df630SAndroid Build Coastguard Worker if (seed_size * 2 != strlen(endorsement_seed_str)) {
3800*4f2df630SAndroid Build Coastguard Worker printf("Invalid seed %s\n", endorsement_seed_str);
3801*4f2df630SAndroid Build Coastguard Worker return update_error;
3802*4f2df630SAndroid Build Coastguard Worker }
3803*4f2df630SAndroid Build Coastguard Worker
3804*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < seed_size; i++) {
3805*4f2df630SAndroid Build Coastguard Worker int nibble;
3806*4f2df630SAndroid Build Coastguard Worker char c;
3807*4f2df630SAndroid Build Coastguard Worker
3808*4f2df630SAndroid Build Coastguard Worker c = endorsement_seed_str[2 * i];
3809*4f2df630SAndroid Build Coastguard Worker nibble = from_hexascii(c);
3810*4f2df630SAndroid Build Coastguard Worker if (nibble < 0) {
3811*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: Non hex character in seed %c\n",
3812*4f2df630SAndroid Build Coastguard Worker c);
3813*4f2df630SAndroid Build Coastguard Worker return update_error;
3814*4f2df630SAndroid Build Coastguard Worker }
3815*4f2df630SAndroid Build Coastguard Worker endorsement_seed[i] = nibble << 4;
3816*4f2df630SAndroid Build Coastguard Worker
3817*4f2df630SAndroid Build Coastguard Worker c = endorsement_seed_str[2 * i + 1];
3818*4f2df630SAndroid Build Coastguard Worker nibble = from_hexascii(c);
3819*4f2df630SAndroid Build Coastguard Worker if (nibble < 0) {
3820*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error: Non hex character in seed %c\n",
3821*4f2df630SAndroid Build Coastguard Worker c);
3822*4f2df630SAndroid Build Coastguard Worker return update_error;
3823*4f2df630SAndroid Build Coastguard Worker }
3824*4f2df630SAndroid Build Coastguard Worker endorsement_seed[i] |= nibble;
3825*4f2df630SAndroid Build Coastguard Worker }
3826*4f2df630SAndroid Build Coastguard Worker
3827*4f2df630SAndroid Build Coastguard Worker printf("Setting seed: %s\n", endorsement_seed_str);
3828*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_ENDORSEMENT_SEED,
3829*4f2df630SAndroid Build Coastguard Worker endorsement_seed, seed_size, response_seed,
3830*4f2df630SAndroid Build Coastguard Worker &response_size);
3831*4f2df630SAndroid Build Coastguard Worker if (rv == VENDOR_RC_NOT_ALLOWED) {
3832*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Seed already set\n");
3833*4f2df630SAndroid Build Coastguard Worker return update_error;
3834*4f2df630SAndroid Build Coastguard Worker }
3835*4f2df630SAndroid Build Coastguard Worker if (rv) {
3836*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error sending vendor command %d\n", rv);
3837*4f2df630SAndroid Build Coastguard Worker return update_error;
3838*4f2df630SAndroid Build Coastguard Worker }
3839*4f2df630SAndroid Build Coastguard Worker printf("Updated endorsement key seed.\n");
3840*4f2df630SAndroid Build Coastguard Worker return 0;
3841*4f2df630SAndroid Build Coastguard Worker }
3842*4f2df630SAndroid Build Coastguard Worker
3843*4f2df630SAndroid Build Coastguard Worker /*
3844*4f2df630SAndroid Build Coastguard Worker * Retrieve the RMA authentication challenge from the Cr50, print out the
3845*4f2df630SAndroid Build Coastguard Worker * challenge on the console, then prompt the user for the authentication code,
3846*4f2df630SAndroid Build Coastguard Worker * and send the code back to Cr50. The Cr50 would report if the code matched
3847*4f2df630SAndroid Build Coastguard Worker * its expectations or not. Output in a machine-friendly format if
3848*4f2df630SAndroid Build Coastguard Worker * show_machine_output is true.
3849*4f2df630SAndroid Build Coastguard Worker */
process_rma(struct transfer_descriptor * td,const char * authcode,bool show_machine_output)3850*4f2df630SAndroid Build Coastguard Worker static void process_rma(struct transfer_descriptor *td, const char *authcode,
3851*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
3852*4f2df630SAndroid Build Coastguard Worker {
3853*4f2df630SAndroid Build Coastguard Worker char rma_response[81];
3854*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(rma_response);
3855*4f2df630SAndroid Build Coastguard Worker size_t i;
3856*4f2df630SAndroid Build Coastguard Worker size_t auth_size = 0;
3857*4f2df630SAndroid Build Coastguard Worker
3858*4f2df630SAndroid Build Coastguard Worker if (!authcode) {
3859*4f2df630SAndroid Build Coastguard Worker send_vendor_command(td, VENDOR_CC_RMA_CHALLENGE_RESPONSE, NULL,
3860*4f2df630SAndroid Build Coastguard Worker 0, rma_response, &response_size);
3861*4f2df630SAndroid Build Coastguard Worker
3862*4f2df630SAndroid Build Coastguard Worker if (response_size == 1) {
3863*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "error %d\n", rma_response[0]);
3864*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer)
3865*4f2df630SAndroid Build Coastguard Worker shut_down(&td->uep);
3866*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3867*4f2df630SAndroid Build Coastguard Worker }
3868*4f2df630SAndroid Build Coastguard Worker
3869*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
3870*4f2df630SAndroid Build Coastguard Worker rma_response[response_size] = '\0';
3871*4f2df630SAndroid Build Coastguard Worker print_machine_output("CHALLENGE", "%s", rma_response);
3872*4f2df630SAndroid Build Coastguard Worker } else {
3873*4f2df630SAndroid Build Coastguard Worker printf("Challenge:");
3874*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < response_size; i++) {
3875*4f2df630SAndroid Build Coastguard Worker if (!(i % 5)) {
3876*4f2df630SAndroid Build Coastguard Worker if (!(i % 40))
3877*4f2df630SAndroid Build Coastguard Worker printf("\n");
3878*4f2df630SAndroid Build Coastguard Worker printf(" ");
3879*4f2df630SAndroid Build Coastguard Worker }
3880*4f2df630SAndroid Build Coastguard Worker printf("%c", rma_response[i]);
3881*4f2df630SAndroid Build Coastguard Worker }
3882*4f2df630SAndroid Build Coastguard Worker printf("\n");
3883*4f2df630SAndroid Build Coastguard Worker }
3884*4f2df630SAndroid Build Coastguard Worker return;
3885*4f2df630SAndroid Build Coastguard Worker }
3886*4f2df630SAndroid Build Coastguard Worker
3887*4f2df630SAndroid Build Coastguard Worker if (!*authcode) {
3888*4f2df630SAndroid Build Coastguard Worker printf("Empty response.\n");
3889*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3890*4f2df630SAndroid Build Coastguard Worker return;
3891*4f2df630SAndroid Build Coastguard Worker }
3892*4f2df630SAndroid Build Coastguard Worker
3893*4f2df630SAndroid Build Coastguard Worker if (!strcmp(authcode, "disable")) {
3894*4f2df630SAndroid Build Coastguard Worker printf("Invalid arg. Try using 'gsctool -F disable'\n");
3895*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3896*4f2df630SAndroid Build Coastguard Worker return;
3897*4f2df630SAndroid Build Coastguard Worker }
3898*4f2df630SAndroid Build Coastguard Worker
3899*4f2df630SAndroid Build Coastguard Worker printf("Processing response...\n");
3900*4f2df630SAndroid Build Coastguard Worker auth_size = strlen(authcode);
3901*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(rma_response);
3902*4f2df630SAndroid Build Coastguard Worker
3903*4f2df630SAndroid Build Coastguard Worker send_vendor_command(td, VENDOR_CC_RMA_CHALLENGE_RESPONSE, authcode,
3904*4f2df630SAndroid Build Coastguard Worker auth_size, rma_response, &response_size);
3905*4f2df630SAndroid Build Coastguard Worker
3906*4f2df630SAndroid Build Coastguard Worker if (response_size == 1) {
3907*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "\nrma unlock failed, code %d ", *rma_response);
3908*4f2df630SAndroid Build Coastguard Worker switch (*rma_response) {
3909*4f2df630SAndroid Build Coastguard Worker case VENDOR_RC_BOGUS_ARGS:
3910*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "(wrong authcode size)\n");
3911*4f2df630SAndroid Build Coastguard Worker break;
3912*4f2df630SAndroid Build Coastguard Worker case VENDOR_RC_INTERNAL_ERROR:
3913*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "(authcode mismatch)\n");
3914*4f2df630SAndroid Build Coastguard Worker break;
3915*4f2df630SAndroid Build Coastguard Worker default:
3916*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "(unknown error)\n");
3917*4f2df630SAndroid Build Coastguard Worker break;
3918*4f2df630SAndroid Build Coastguard Worker }
3919*4f2df630SAndroid Build Coastguard Worker if (td->ep_type == usb_xfer)
3920*4f2df630SAndroid Build Coastguard Worker shut_down(&td->uep);
3921*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3922*4f2df630SAndroid Build Coastguard Worker }
3923*4f2df630SAndroid Build Coastguard Worker printf("RMA unlock succeeded.\n");
3924*4f2df630SAndroid Build Coastguard Worker }
3925*4f2df630SAndroid Build Coastguard Worker
3926*4f2df630SAndroid Build Coastguard Worker /*
3927*4f2df630SAndroid Build Coastguard Worker * Enable or disable factory mode. Factory mode will only be enabled if HW
3928*4f2df630SAndroid Build Coastguard Worker * write protect is removed.
3929*4f2df630SAndroid Build Coastguard Worker */
process_factory_mode(struct transfer_descriptor * td,const char * arg)3930*4f2df630SAndroid Build Coastguard Worker static void process_factory_mode(struct transfer_descriptor *td,
3931*4f2df630SAndroid Build Coastguard Worker const char *arg)
3932*4f2df630SAndroid Build Coastguard Worker {
3933*4f2df630SAndroid Build Coastguard Worker uint8_t rma_response;
3934*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(rma_response);
3935*4f2df630SAndroid Build Coastguard Worker char *cmd_str;
3936*4f2df630SAndroid Build Coastguard Worker int rv;
3937*4f2df630SAndroid Build Coastguard Worker uint16_t subcommand;
3938*4f2df630SAndroid Build Coastguard Worker
3939*4f2df630SAndroid Build Coastguard Worker if (!strcasecmp(arg, "disable")) {
3940*4f2df630SAndroid Build Coastguard Worker subcommand = VENDOR_CC_DISABLE_FACTORY;
3941*4f2df630SAndroid Build Coastguard Worker cmd_str = "dis";
3942*4f2df630SAndroid Build Coastguard Worker } else if (!strcasecmp(arg, "enable")) {
3943*4f2df630SAndroid Build Coastguard Worker subcommand = VENDOR_CC_RESET_FACTORY;
3944*4f2df630SAndroid Build Coastguard Worker cmd_str = "en";
3945*4f2df630SAndroid Build Coastguard Worker
3946*4f2df630SAndroid Build Coastguard Worker } else {
3947*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Invalid factory mode arg %s", arg);
3948*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3949*4f2df630SAndroid Build Coastguard Worker }
3950*4f2df630SAndroid Build Coastguard Worker
3951*4f2df630SAndroid Build Coastguard Worker printf("%sabling factory mode\n", cmd_str);
3952*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, subcommand, NULL, 0, &rma_response,
3953*4f2df630SAndroid Build Coastguard Worker &response_size);
3954*4f2df630SAndroid Build Coastguard Worker if (rv) {
3955*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
3956*4f2df630SAndroid Build Coastguard Worker "Failed %sabling factory mode\nvc error "
3957*4f2df630SAndroid Build Coastguard Worker "%d\n",
3958*4f2df630SAndroid Build Coastguard Worker cmd_str, rv);
3959*4f2df630SAndroid Build Coastguard Worker if (response_size == 1)
3960*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "ec error %d\n", rma_response);
3961*4f2df630SAndroid Build Coastguard Worker exit(update_error);
3962*4f2df630SAndroid Build Coastguard Worker }
3963*4f2df630SAndroid Build Coastguard Worker printf("Factory %sable succeeded.\n", cmd_str);
3964*4f2df630SAndroid Build Coastguard Worker }
3965*4f2df630SAndroid Build Coastguard Worker
report_version(void)3966*4f2df630SAndroid Build Coastguard Worker static void report_version(void)
3967*4f2df630SAndroid Build Coastguard Worker {
3968*4f2df630SAndroid Build Coastguard Worker /* Get version from the generated file, ignore the underscore prefix. */
3969*4f2df630SAndroid Build Coastguard Worker const char *v = strchr(VERSION, '_');
3970*4f2df630SAndroid Build Coastguard Worker
3971*4f2df630SAndroid Build Coastguard Worker printf("Version: %s, built on %s by %s\n", v ? v + 1 : "?", DATE,
3972*4f2df630SAndroid Build Coastguard Worker BUILDER);
3973*4f2df630SAndroid Build Coastguard Worker exit(0);
3974*4f2df630SAndroid Build Coastguard Worker }
3975*4f2df630SAndroid Build Coastguard Worker
3976*4f2df630SAndroid Build Coastguard Worker /*
3977*4f2df630SAndroid Build Coastguard Worker * Either change or query TPM mode value.
3978*4f2df630SAndroid Build Coastguard Worker */
process_tpm_mode(struct transfer_descriptor * td,const char * arg)3979*4f2df630SAndroid Build Coastguard Worker static int process_tpm_mode(struct transfer_descriptor *td, const char *arg)
3980*4f2df630SAndroid Build Coastguard Worker {
3981*4f2df630SAndroid Build Coastguard Worker int rv;
3982*4f2df630SAndroid Build Coastguard Worker size_t command_size;
3983*4f2df630SAndroid Build Coastguard Worker size_t response_size;
3984*4f2df630SAndroid Build Coastguard Worker uint8_t response;
3985*4f2df630SAndroid Build Coastguard Worker uint8_t command_body;
3986*4f2df630SAndroid Build Coastguard Worker
3987*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(response);
3988*4f2df630SAndroid Build Coastguard Worker if (!arg) {
3989*4f2df630SAndroid Build Coastguard Worker command_size = 0;
3990*4f2df630SAndroid Build Coastguard Worker } else if (!strcasecmp(arg, "disable")) {
3991*4f2df630SAndroid Build Coastguard Worker command_size = sizeof(command_body);
3992*4f2df630SAndroid Build Coastguard Worker command_body = (uint8_t)TPM_MODE_DISABLED;
3993*4f2df630SAndroid Build Coastguard Worker } else if (!strcasecmp(arg, "enable")) {
3994*4f2df630SAndroid Build Coastguard Worker command_size = sizeof(command_body);
3995*4f2df630SAndroid Build Coastguard Worker command_body = (uint8_t)TPM_MODE_ENABLED;
3996*4f2df630SAndroid Build Coastguard Worker } else {
3997*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Invalid tpm mode arg: %s.\n", arg);
3998*4f2df630SAndroid Build Coastguard Worker return update_error;
3999*4f2df630SAndroid Build Coastguard Worker }
4000*4f2df630SAndroid Build Coastguard Worker
4001*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_TPM_MODE, &command_body,
4002*4f2df630SAndroid Build Coastguard Worker command_size, &response, &response_size);
4003*4f2df630SAndroid Build Coastguard Worker if (rv) {
4004*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d in setting TPM mode.\n", rv);
4005*4f2df630SAndroid Build Coastguard Worker return update_error;
4006*4f2df630SAndroid Build Coastguard Worker }
4007*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(response)) {
4008*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
4009*4f2df630SAndroid Build Coastguard Worker "Error in the size of response,"
4010*4f2df630SAndroid Build Coastguard Worker " %zu.\n",
4011*4f2df630SAndroid Build Coastguard Worker response_size);
4012*4f2df630SAndroid Build Coastguard Worker return update_error;
4013*4f2df630SAndroid Build Coastguard Worker }
4014*4f2df630SAndroid Build Coastguard Worker if (response >= TPM_MODE_MAX) {
4015*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
4016*4f2df630SAndroid Build Coastguard Worker "Error in the value of response,"
4017*4f2df630SAndroid Build Coastguard Worker " %d.\n",
4018*4f2df630SAndroid Build Coastguard Worker response);
4019*4f2df630SAndroid Build Coastguard Worker return update_error;
4020*4f2df630SAndroid Build Coastguard Worker }
4021*4f2df630SAndroid Build Coastguard Worker
4022*4f2df630SAndroid Build Coastguard Worker printf("TPM Mode: %s (%d)\n",
4023*4f2df630SAndroid Build Coastguard Worker (response == TPM_MODE_DISABLED) ? "disabled" : "enabled",
4024*4f2df630SAndroid Build Coastguard Worker response);
4025*4f2df630SAndroid Build Coastguard Worker
4026*4f2df630SAndroid Build Coastguard Worker return rv;
4027*4f2df630SAndroid Build Coastguard Worker }
4028*4f2df630SAndroid Build Coastguard Worker
4029*4f2df630SAndroid Build Coastguard Worker #define MAX_PAYLOAD_SIZE 256
4030*4f2df630SAndroid Build Coastguard Worker struct parsed_flog_entry {
4031*4f2df630SAndroid Build Coastguard Worker bool end_of_list;
4032*4f2df630SAndroid Build Coastguard Worker char payload[MAX_PAYLOAD_SIZE];
4033*4f2df630SAndroid Build Coastguard Worker size_t payload_size;
4034*4f2df630SAndroid Build Coastguard Worker uint64_t raw_timestamp;
4035*4f2df630SAndroid Build Coastguard Worker time_t timestamp;
4036*4f2df630SAndroid Build Coastguard Worker uint32_t event_type;
4037*4f2df630SAndroid Build Coastguard Worker bool timestamp_reliable;
4038*4f2df630SAndroid Build Coastguard Worker };
4039*4f2df630SAndroid Build Coastguard Worker
pop_flog_dt(struct transfer_descriptor * td,struct parsed_flog_entry * parsed_entry)4040*4f2df630SAndroid Build Coastguard Worker static int pop_flog_dt(struct transfer_descriptor *td,
4041*4f2df630SAndroid Build Coastguard Worker struct parsed_flog_entry *parsed_entry)
4042*4f2df630SAndroid Build Coastguard Worker {
4043*4f2df630SAndroid Build Coastguard Worker union dt_entry_u entry;
4044*4f2df630SAndroid Build Coastguard Worker size_t resp_size = sizeof(entry);
4045*4f2df630SAndroid Build Coastguard Worker int rv = send_vendor_command(td, VENDOR_CC_POP_LOG_ENTRY_MS,
4046*4f2df630SAndroid Build Coastguard Worker &parsed_entry->raw_timestamp,
4047*4f2df630SAndroid Build Coastguard Worker sizeof(parsed_entry->raw_timestamp),
4048*4f2df630SAndroid Build Coastguard Worker &entry, &resp_size);
4049*4f2df630SAndroid Build Coastguard Worker if (rv)
4050*4f2df630SAndroid Build Coastguard Worker return rv;
4051*4f2df630SAndroid Build Coastguard Worker if (resp_size == 0) {
4052*4f2df630SAndroid Build Coastguard Worker parsed_entry->end_of_list = true;
4053*4f2df630SAndroid Build Coastguard Worker return 0;
4054*4f2df630SAndroid Build Coastguard Worker }
4055*4f2df630SAndroid Build Coastguard Worker parsed_entry->event_type = entry.evt.event_type;
4056*4f2df630SAndroid Build Coastguard Worker parsed_entry->payload_size =
4057*4f2df630SAndroid Build Coastguard Worker MIN(entry.evt.size - sizeof(entry.evt.event_type),
4058*4f2df630SAndroid Build Coastguard Worker MAX_PAYLOAD_SIZE);
4059*4f2df630SAndroid Build Coastguard Worker memcpy(parsed_entry->payload, entry.evt.payload,
4060*4f2df630SAndroid Build Coastguard Worker parsed_entry->payload_size);
4061*4f2df630SAndroid Build Coastguard Worker parsed_entry->raw_timestamp = entry.evt.time;
4062*4f2df630SAndroid Build Coastguard Worker parsed_entry->timestamp =
4063*4f2df630SAndroid Build Coastguard Worker (parsed_entry->raw_timestamp & ~(1ULL << 63)) / 1000;
4064*4f2df630SAndroid Build Coastguard Worker parsed_entry->timestamp_reliable =
4065*4f2df630SAndroid Build Coastguard Worker (parsed_entry->raw_timestamp >> 63) == 0;
4066*4f2df630SAndroid Build Coastguard Worker return rv;
4067*4f2df630SAndroid Build Coastguard Worker }
4068*4f2df630SAndroid Build Coastguard Worker
pop_flog(struct transfer_descriptor * td,struct parsed_flog_entry * parsed_entry)4069*4f2df630SAndroid Build Coastguard Worker static int pop_flog(struct transfer_descriptor *td,
4070*4f2df630SAndroid Build Coastguard Worker struct parsed_flog_entry *parsed_entry)
4071*4f2df630SAndroid Build Coastguard Worker {
4072*4f2df630SAndroid Build Coastguard Worker union entry_u entry;
4073*4f2df630SAndroid Build Coastguard Worker size_t resp_size = sizeof(entry);
4074*4f2df630SAndroid Build Coastguard Worker uint32_t ts = (uint32_t)parsed_entry->raw_timestamp;
4075*4f2df630SAndroid Build Coastguard Worker int rv = send_vendor_command(td, VENDOR_CC_POP_LOG_ENTRY, &ts,
4076*4f2df630SAndroid Build Coastguard Worker sizeof(ts), &entry, &resp_size);
4077*4f2df630SAndroid Build Coastguard Worker if (rv)
4078*4f2df630SAndroid Build Coastguard Worker return rv;
4079*4f2df630SAndroid Build Coastguard Worker if (resp_size == 0) {
4080*4f2df630SAndroid Build Coastguard Worker parsed_entry->end_of_list = true;
4081*4f2df630SAndroid Build Coastguard Worker return 0;
4082*4f2df630SAndroid Build Coastguard Worker }
4083*4f2df630SAndroid Build Coastguard Worker parsed_entry->event_type = entry.r.type;
4084*4f2df630SAndroid Build Coastguard Worker parsed_entry->payload_size =
4085*4f2df630SAndroid Build Coastguard Worker MIN(FLASH_LOG_PAYLOAD_SIZE(entry.r.size), MAX_PAYLOAD_SIZE);
4086*4f2df630SAndroid Build Coastguard Worker memcpy(parsed_entry->payload, entry.r.payload,
4087*4f2df630SAndroid Build Coastguard Worker parsed_entry->payload_size);
4088*4f2df630SAndroid Build Coastguard Worker parsed_entry->raw_timestamp = entry.r.timestamp;
4089*4f2df630SAndroid Build Coastguard Worker parsed_entry->timestamp = entry.r.timestamp;
4090*4f2df630SAndroid Build Coastguard Worker parsed_entry->timestamp_reliable = true;
4091*4f2df630SAndroid Build Coastguard Worker return rv;
4092*4f2df630SAndroid Build Coastguard Worker }
4093*4f2df630SAndroid Build Coastguard Worker
4094*4f2df630SAndroid Build Coastguard Worker /*
4095*4f2df630SAndroid Build Coastguard Worker * Retrieve from H1 flash log entries which are newer than the passed in
4096*4f2df630SAndroid Build Coastguard Worker * timestamp.
4097*4f2df630SAndroid Build Coastguard Worker *
4098*4f2df630SAndroid Build Coastguard Worker * On error retry a few times just in case flash log is locked by a concurrent
4099*4f2df630SAndroid Build Coastguard Worker * access.
4100*4f2df630SAndroid Build Coastguard Worker */
process_get_flog(struct transfer_descriptor * td,uint64_t prev_stamp,bool show_machine_output)4101*4f2df630SAndroid Build Coastguard Worker static int process_get_flog(struct transfer_descriptor *td, uint64_t prev_stamp,
4102*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
4103*4f2df630SAndroid Build Coastguard Worker {
4104*4f2df630SAndroid Build Coastguard Worker int rv;
4105*4f2df630SAndroid Build Coastguard Worker const int max_retries = 3;
4106*4f2df630SAndroid Build Coastguard Worker int retries = max_retries;
4107*4f2df630SAndroid Build Coastguard Worker bool time_zone_reported = false;
4108*4f2df630SAndroid Build Coastguard Worker
4109*4f2df630SAndroid Build Coastguard Worker while (retries--) {
4110*4f2df630SAndroid Build Coastguard Worker struct parsed_flog_entry entry = { 0 };
4111*4f2df630SAndroid Build Coastguard Worker entry.raw_timestamp = prev_stamp;
4112*4f2df630SAndroid Build Coastguard Worker size_t i;
4113*4f2df630SAndroid Build Coastguard Worker struct tm loc_time;
4114*4f2df630SAndroid Build Coastguard Worker char date_str[25];
4115*4f2df630SAndroid Build Coastguard Worker if (is_ti50_device()) {
4116*4f2df630SAndroid Build Coastguard Worker rv = pop_flog_dt(td, &entry);
4117*4f2df630SAndroid Build Coastguard Worker } else {
4118*4f2df630SAndroid Build Coastguard Worker rv = pop_flog(td, &entry);
4119*4f2df630SAndroid Build Coastguard Worker }
4120*4f2df630SAndroid Build Coastguard Worker
4121*4f2df630SAndroid Build Coastguard Worker if (rv) {
4122*4f2df630SAndroid Build Coastguard Worker /*
4123*4f2df630SAndroid Build Coastguard Worker * Flash log could be momentarily locked by a
4124*4f2df630SAndroid Build Coastguard Worker * concurrent access, let it settle and try again, 10
4125*4f2df630SAndroid Build Coastguard Worker * ms should be enough.
4126*4f2df630SAndroid Build Coastguard Worker */
4127*4f2df630SAndroid Build Coastguard Worker usleep(10 * 1000);
4128*4f2df630SAndroid Build Coastguard Worker continue;
4129*4f2df630SAndroid Build Coastguard Worker }
4130*4f2df630SAndroid Build Coastguard Worker
4131*4f2df630SAndroid Build Coastguard Worker if (entry.end_of_list)
4132*4f2df630SAndroid Build Coastguard Worker return 0;
4133*4f2df630SAndroid Build Coastguard Worker
4134*4f2df630SAndroid Build Coastguard Worker prev_stamp = entry.raw_timestamp;
4135*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
4136*4f2df630SAndroid Build Coastguard Worker printf("%10" PRIu64 ":%02x", prev_stamp,
4137*4f2df630SAndroid Build Coastguard Worker entry.event_type);
4138*4f2df630SAndroid Build Coastguard Worker } else {
4139*4f2df630SAndroid Build Coastguard Worker localtime_r(&entry.timestamp, &loc_time);
4140*4f2df630SAndroid Build Coastguard Worker
4141*4f2df630SAndroid Build Coastguard Worker if (!time_zone_reported) {
4142*4f2df630SAndroid Build Coastguard Worker strftime(date_str, sizeof(date_str), "%Z",
4143*4f2df630SAndroid Build Coastguard Worker &loc_time);
4144*4f2df630SAndroid Build Coastguard Worker printf("Log time zone is %s\n", date_str);
4145*4f2df630SAndroid Build Coastguard Worker time_zone_reported = true;
4146*4f2df630SAndroid Build Coastguard Worker }
4147*4f2df630SAndroid Build Coastguard Worker
4148*4f2df630SAndroid Build Coastguard Worker /* Date format is MMM DD YY HH:mm:ss */
4149*4f2df630SAndroid Build Coastguard Worker strftime(date_str, sizeof(date_str), "%b %d %y %T",
4150*4f2df630SAndroid Build Coastguard Worker &loc_time);
4151*4f2df630SAndroid Build Coastguard Worker printf("%s : %02x", date_str, entry.event_type);
4152*4f2df630SAndroid Build Coastguard Worker }
4153*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < entry.payload_size; i++)
4154*4f2df630SAndroid Build Coastguard Worker printf(" %02x", entry.payload[i]);
4155*4f2df630SAndroid Build Coastguard Worker if (entry.timestamp_reliable == false)
4156*4f2df630SAndroid Build Coastguard Worker printf(" -- TIMESTAMP UNRELIABLE!");
4157*4f2df630SAndroid Build Coastguard Worker printf("\n");
4158*4f2df630SAndroid Build Coastguard Worker retries = max_retries;
4159*4f2df630SAndroid Build Coastguard Worker }
4160*4f2df630SAndroid Build Coastguard Worker
4161*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "%s: error %d\n", __func__, rv);
4162*4f2df630SAndroid Build Coastguard Worker
4163*4f2df630SAndroid Build Coastguard Worker return rv;
4164*4f2df630SAndroid Build Coastguard Worker }
4165*4f2df630SAndroid Build Coastguard Worker
process_tstamp(struct transfer_descriptor * td,const char * tstamp_ascii)4166*4f2df630SAndroid Build Coastguard Worker static int process_tstamp(struct transfer_descriptor *td,
4167*4f2df630SAndroid Build Coastguard Worker const char *tstamp_ascii)
4168*4f2df630SAndroid Build Coastguard Worker {
4169*4f2df630SAndroid Build Coastguard Worker char *e;
4170*4f2df630SAndroid Build Coastguard Worker size_t expected_response_size;
4171*4f2df630SAndroid Build Coastguard Worker size_t message_size;
4172*4f2df630SAndroid Build Coastguard Worker size_t response_size;
4173*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4174*4f2df630SAndroid Build Coastguard Worker uint32_t tstamp = 0;
4175*4f2df630SAndroid Build Coastguard Worker uint8_t max_response[sizeof(uint32_t)];
4176*4f2df630SAndroid Build Coastguard Worker
4177*4f2df630SAndroid Build Coastguard Worker if (tstamp_ascii) {
4178*4f2df630SAndroid Build Coastguard Worker tstamp = strtoul(tstamp_ascii, &e, 10);
4179*4f2df630SAndroid Build Coastguard Worker if (*e) {
4180*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "invalid base timestamp value \"%s\"\n",
4181*4f2df630SAndroid Build Coastguard Worker tstamp_ascii);
4182*4f2df630SAndroid Build Coastguard Worker return -1;
4183*4f2df630SAndroid Build Coastguard Worker }
4184*4f2df630SAndroid Build Coastguard Worker tstamp = htobe32(tstamp);
4185*4f2df630SAndroid Build Coastguard Worker expected_response_size = 0;
4186*4f2df630SAndroid Build Coastguard Worker message_size = sizeof(tstamp);
4187*4f2df630SAndroid Build Coastguard Worker } else {
4188*4f2df630SAndroid Build Coastguard Worker expected_response_size = 4;
4189*4f2df630SAndroid Build Coastguard Worker message_size = 0;
4190*4f2df630SAndroid Build Coastguard Worker }
4191*4f2df630SAndroid Build Coastguard Worker
4192*4f2df630SAndroid Build Coastguard Worker response_size = sizeof(max_response);
4193*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_FLOG_TIMESTAMP, &tstamp,
4194*4f2df630SAndroid Build Coastguard Worker message_size, max_response, &response_size);
4195*4f2df630SAndroid Build Coastguard Worker
4196*4f2df630SAndroid Build Coastguard Worker if (rv) {
4197*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "error: return value %d\n", rv);
4198*4f2df630SAndroid Build Coastguard Worker return rv;
4199*4f2df630SAndroid Build Coastguard Worker }
4200*4f2df630SAndroid Build Coastguard Worker if (response_size != expected_response_size) {
4201*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "error: got %zd bytes, expected %zd\n",
4202*4f2df630SAndroid Build Coastguard Worker response_size, expected_response_size);
4203*4f2df630SAndroid Build Coastguard Worker return -1; /* Should never happen. */
4204*4f2df630SAndroid Build Coastguard Worker }
4205*4f2df630SAndroid Build Coastguard Worker
4206*4f2df630SAndroid Build Coastguard Worker if (response_size) {
4207*4f2df630SAndroid Build Coastguard Worker memcpy(&tstamp, max_response, sizeof(tstamp));
4208*4f2df630SAndroid Build Coastguard Worker printf("Current H1 time is %d\n", be32toh(tstamp));
4209*4f2df630SAndroid Build Coastguard Worker }
4210*4f2df630SAndroid Build Coastguard Worker return 0;
4211*4f2df630SAndroid Build Coastguard Worker }
4212*4f2df630SAndroid Build Coastguard Worker
process_reboot_gsc(struct transfer_descriptor * td,size_t timeout_ms)4213*4f2df630SAndroid Build Coastguard Worker static int process_reboot_gsc(struct transfer_descriptor *td, size_t timeout_ms)
4214*4f2df630SAndroid Build Coastguard Worker {
4215*4f2df630SAndroid Build Coastguard Worker /* Reboot timeout in milliseconds.
4216*4f2df630SAndroid Build Coastguard Worker * Maximum value is 1000ms on Ti50.
4217*4f2df630SAndroid Build Coastguard Worker */
4218*4f2df630SAndroid Build Coastguard Worker uint16_t msg = htobe16((uint16_t)timeout_ms);
4219*4f2df630SAndroid Build Coastguard Worker int rv = 0;
4220*4f2df630SAndroid Build Coastguard Worker
4221*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_IMMEDIATE_RESET, &msg,
4222*4f2df630SAndroid Build Coastguard Worker sizeof(msg), NULL, 0);
4223*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4224*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d sending immediate reset command\n",
4225*4f2df630SAndroid Build Coastguard Worker rv);
4226*4f2df630SAndroid Build Coastguard Worker return update_error;
4227*4f2df630SAndroid Build Coastguard Worker }
4228*4f2df630SAndroid Build Coastguard Worker
4229*4f2df630SAndroid Build Coastguard Worker return 0;
4230*4f2df630SAndroid Build Coastguard Worker }
4231*4f2df630SAndroid Build Coastguard Worker
process_start_apro_verify(struct transfer_descriptor * td)4232*4f2df630SAndroid Build Coastguard Worker static int process_start_apro_verify(struct transfer_descriptor *td)
4233*4f2df630SAndroid Build Coastguard Worker {
4234*4f2df630SAndroid Build Coastguard Worker int rv = 0;
4235*4f2df630SAndroid Build Coastguard Worker
4236*4f2df630SAndroid Build Coastguard Worker /*
4237*4f2df630SAndroid Build Coastguard Worker * For Ti50, we need to restart GSC to perform AP RO verification again.
4238*4f2df630SAndroid Build Coastguard Worker */
4239*4f2df630SAndroid Build Coastguard Worker if (is_ti50_device())
4240*4f2df630SAndroid Build Coastguard Worker return process_reboot_gsc(td, 1000);
4241*4f2df630SAndroid Build Coastguard Worker
4242*4f2df630SAndroid Build Coastguard Worker /* If H1 chip, then send vendor command to start AP RO verification */
4243*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_AP_RO_VALIDATE, NULL, 0, NULL,
4244*4f2df630SAndroid Build Coastguard Worker NULL);
4245*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4246*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Error %d starting RO verify\n", rv);
4247*4f2df630SAndroid Build Coastguard Worker return update_error;
4248*4f2df630SAndroid Build Coastguard Worker }
4249*4f2df630SAndroid Build Coastguard Worker
4250*4f2df630SAndroid Build Coastguard Worker return 0;
4251*4f2df630SAndroid Build Coastguard Worker }
4252*4f2df630SAndroid Build Coastguard Worker
4253*4f2df630SAndroid Build Coastguard Worker /*
4254*4f2df630SAndroid Build Coastguard Worker * Search the passed in zero terminated array of options_map structures for
4255*4f2df630SAndroid Build Coastguard Worker * option 'option'.
4256*4f2df630SAndroid Build Coastguard Worker *
4257*4f2df630SAndroid Build Coastguard Worker * If found - set the corresponding integer to 1 and return 1. If not found -
4258*4f2df630SAndroid Build Coastguard Worker * return 0.
4259*4f2df630SAndroid Build Coastguard Worker */
check_boolean(const struct options_map * omap,char option)4260*4f2df630SAndroid Build Coastguard Worker static int check_boolean(const struct options_map *omap, char option)
4261*4f2df630SAndroid Build Coastguard Worker {
4262*4f2df630SAndroid Build Coastguard Worker do {
4263*4f2df630SAndroid Build Coastguard Worker if (omap->opt != option)
4264*4f2df630SAndroid Build Coastguard Worker continue;
4265*4f2df630SAndroid Build Coastguard Worker
4266*4f2df630SAndroid Build Coastguard Worker *omap->flag = 1;
4267*4f2df630SAndroid Build Coastguard Worker return 1;
4268*4f2df630SAndroid Build Coastguard Worker } while ((++omap)->opt);
4269*4f2df630SAndroid Build Coastguard Worker
4270*4f2df630SAndroid Build Coastguard Worker return 0;
4271*4f2df630SAndroid Build Coastguard Worker }
4272*4f2df630SAndroid Build Coastguard Worker
4273*4f2df630SAndroid Build Coastguard Worker /*
4274*4f2df630SAndroid Build Coastguard Worker * Set the long_opts table and short_opts string.
4275*4f2df630SAndroid Build Coastguard Worker *
4276*4f2df630SAndroid Build Coastguard Worker * This function allows to avoid maintaining two command line option
4277*4f2df630SAndroid Build Coastguard Worker * descriptions, for short and long forms.
4278*4f2df630SAndroid Build Coastguard Worker *
4279*4f2df630SAndroid Build Coastguard Worker * The long_opts table is built based on the cmd_line_options table contents,
4280*4f2df630SAndroid Build Coastguard Worker * and the short form is built based on the long_opts table contents.
4281*4f2df630SAndroid Build Coastguard Worker *
4282*4f2df630SAndroid Build Coastguard Worker * The 'required_argument' short options are followed by ':'.
4283*4f2df630SAndroid Build Coastguard Worker *
4284*4f2df630SAndroid Build Coastguard Worker * The passed in long_opts array and short_opts string are guaranteed to
4285*4f2df630SAndroid Build Coastguard Worker * accommodate all necessary objects/characters.
4286*4f2df630SAndroid Build Coastguard Worker */
set_opt_descriptors(struct option * long_opts,char * short_opts)4287*4f2df630SAndroid Build Coastguard Worker static void set_opt_descriptors(struct option *long_opts, char *short_opts)
4288*4f2df630SAndroid Build Coastguard Worker {
4289*4f2df630SAndroid Build Coastguard Worker size_t i;
4290*4f2df630SAndroid Build Coastguard Worker int j;
4291*4f2df630SAndroid Build Coastguard Worker
4292*4f2df630SAndroid Build Coastguard Worker for (i = j = 0; i < ARRAY_SIZE(cmd_line_options); i++) {
4293*4f2df630SAndroid Build Coastguard Worker long_opts[i] = cmd_line_options[i].opt;
4294*4f2df630SAndroid Build Coastguard Worker short_opts[j++] = long_opts[i].val;
4295*4f2df630SAndroid Build Coastguard Worker if (long_opts[i].has_arg == required_argument)
4296*4f2df630SAndroid Build Coastguard Worker short_opts[j++] = ':';
4297*4f2df630SAndroid Build Coastguard Worker }
4298*4f2df630SAndroid Build Coastguard Worker }
4299*4f2df630SAndroid Build Coastguard Worker
4300*4f2df630SAndroid Build Coastguard Worker /*
4301*4f2df630SAndroid Build Coastguard Worker * Find the long_opts table index where .val field is set to the passed in
4302*4f2df630SAndroid Build Coastguard Worker * short option value.
4303*4f2df630SAndroid Build Coastguard Worker */
get_longindex(int short_opt,const struct option * long_opts)4304*4f2df630SAndroid Build Coastguard Worker static int get_longindex(int short_opt, const struct option *long_opts)
4305*4f2df630SAndroid Build Coastguard Worker {
4306*4f2df630SAndroid Build Coastguard Worker int i;
4307*4f2df630SAndroid Build Coastguard Worker
4308*4f2df630SAndroid Build Coastguard Worker for (i = 0; long_opts[i].name; i++)
4309*4f2df630SAndroid Build Coastguard Worker if (long_opts[i].val == short_opt)
4310*4f2df630SAndroid Build Coastguard Worker return i;
4311*4f2df630SAndroid Build Coastguard Worker
4312*4f2df630SAndroid Build Coastguard Worker /*
4313*4f2df630SAndroid Build Coastguard Worker * We could never come here as the short options list is compiled
4314*4f2df630SAndroid Build Coastguard Worker * based on long options table.
4315*4f2df630SAndroid Build Coastguard Worker */
4316*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Command line error, parameter argument missing\n");
4317*4f2df630SAndroid Build Coastguard Worker exit(1);
4318*4f2df630SAndroid Build Coastguard Worker
4319*4f2df630SAndroid Build Coastguard Worker return -1; /* Not reached. */
4320*4f2df630SAndroid Build Coastguard Worker }
4321*4f2df630SAndroid Build Coastguard Worker
4322*4f2df630SAndroid Build Coastguard Worker /*
4323*4f2df630SAndroid Build Coastguard Worker * Combine searching for command line parameters and optional arguments.
4324*4f2df630SAndroid Build Coastguard Worker *
4325*4f2df630SAndroid Build Coastguard Worker * The canonical short options description string does not allow to specify
4326*4f2df630SAndroid Build Coastguard Worker * that a command line argument expects an optional parameter. but gsctool
4327*4f2df630SAndroid Build Coastguard Worker * users expect to be able to use the following styles for optional
4328*4f2df630SAndroid Build Coastguard Worker * parameters:
4329*4f2df630SAndroid Build Coastguard Worker *
4330*4f2df630SAndroid Build Coastguard Worker * a) -x <param value>
4331*4f2df630SAndroid Build Coastguard Worker * b) --x_long <param_value>
4332*4f2df630SAndroid Build Coastguard Worker * c) --x_long=<param_value>
4333*4f2df630SAndroid Build Coastguard Worker *
4334*4f2df630SAndroid Build Coastguard Worker * Styles a) and b) are not supported standard getopt_long(), this function
4335*4f2df630SAndroid Build Coastguard Worker * adds ability to handle cases a) and b).
4336*4f2df630SAndroid Build Coastguard Worker */
getopt_all(int argc,char * argv[])4337*4f2df630SAndroid Build Coastguard Worker static int getopt_all(int argc, char *argv[])
4338*4f2df630SAndroid Build Coastguard Worker {
4339*4f2df630SAndroid Build Coastguard Worker int longindex = -1;
4340*4f2df630SAndroid Build Coastguard Worker static char short_opts[2 * ARRAY_SIZE(cmd_line_options)] = {};
4341*4f2df630SAndroid Build Coastguard Worker static struct option long_opts[ARRAY_SIZE(cmd_line_options) + 1] = {};
4342*4f2df630SAndroid Build Coastguard Worker int i;
4343*4f2df630SAndroid Build Coastguard Worker
4344*4f2df630SAndroid Build Coastguard Worker if (!short_opts[0])
4345*4f2df630SAndroid Build Coastguard Worker set_opt_descriptors(long_opts, short_opts);
4346*4f2df630SAndroid Build Coastguard Worker
4347*4f2df630SAndroid Build Coastguard Worker i = getopt_long(argc, argv, short_opts, long_opts, &longindex);
4348*4f2df630SAndroid Build Coastguard Worker if (i != -1) {
4349*4f2df630SAndroid Build Coastguard Worker if (longindex < 0) {
4350*4f2df630SAndroid Build Coastguard Worker /*
4351*4f2df630SAndroid Build Coastguard Worker * longindex is not set, this must have been the short
4352*4f2df630SAndroid Build Coastguard Worker * option case, Find the long_opts table index based
4353*4f2df630SAndroid Build Coastguard Worker * on the short option value.
4354*4f2df630SAndroid Build Coastguard Worker */
4355*4f2df630SAndroid Build Coastguard Worker longindex = get_longindex(i, long_opts);
4356*4f2df630SAndroid Build Coastguard Worker }
4357*4f2df630SAndroid Build Coastguard Worker
4358*4f2df630SAndroid Build Coastguard Worker if (long_opts[longindex].has_arg == optional_argument) {
4359*4f2df630SAndroid Build Coastguard Worker /*
4360*4f2df630SAndroid Build Coastguard Worker * This command line option may include an argument,
4361*4f2df630SAndroid Build Coastguard Worker * let's check if it is there as the next token in the
4362*4f2df630SAndroid Build Coastguard Worker * command line.
4363*4f2df630SAndroid Build Coastguard Worker */
4364*4f2df630SAndroid Build Coastguard Worker if (!optarg && argv[optind] && argv[optind][0] != '-')
4365*4f2df630SAndroid Build Coastguard Worker /* Yes, it is. */
4366*4f2df630SAndroid Build Coastguard Worker optarg = argv[optind++];
4367*4f2df630SAndroid Build Coastguard Worker }
4368*4f2df630SAndroid Build Coastguard Worker }
4369*4f2df630SAndroid Build Coastguard Worker
4370*4f2df630SAndroid Build Coastguard Worker return i;
4371*4f2df630SAndroid Build Coastguard Worker }
4372*4f2df630SAndroid Build Coastguard Worker
get_crashlog(struct transfer_descriptor * td)4373*4f2df630SAndroid Build Coastguard Worker static int get_crashlog(struct transfer_descriptor *td)
4374*4f2df630SAndroid Build Coastguard Worker {
4375*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4376*4f2df630SAndroid Build Coastguard Worker uint8_t response[2048] = { 0 };
4377*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4378*4f2df630SAndroid Build Coastguard Worker
4379*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_CRASHLOG, NULL, 0, response,
4380*4f2df630SAndroid Build Coastguard Worker &response_size);
4381*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4382*4f2df630SAndroid Build Coastguard Worker printf("Get crash log failed. (%X)\n", rv);
4383*4f2df630SAndroid Build Coastguard Worker return 1;
4384*4f2df630SAndroid Build Coastguard Worker }
4385*4f2df630SAndroid Build Coastguard Worker
4386*4f2df630SAndroid Build Coastguard Worker for (size_t i = 0; i < response_size; i++) {
4387*4f2df630SAndroid Build Coastguard Worker if (i % 64 == 0 && i > 0)
4388*4f2df630SAndroid Build Coastguard Worker printf("\n");
4389*4f2df630SAndroid Build Coastguard Worker printf("%02x", response[i]);
4390*4f2df630SAndroid Build Coastguard Worker }
4391*4f2df630SAndroid Build Coastguard Worker printf("\n");
4392*4f2df630SAndroid Build Coastguard Worker return 0;
4393*4f2df630SAndroid Build Coastguard Worker }
4394*4f2df630SAndroid Build Coastguard Worker
get_console_logs(struct transfer_descriptor * td)4395*4f2df630SAndroid Build Coastguard Worker static int get_console_logs(struct transfer_descriptor *td)
4396*4f2df630SAndroid Build Coastguard Worker {
4397*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4398*4f2df630SAndroid Build Coastguard Worker uint8_t response[2048] = { 0 };
4399*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4400*4f2df630SAndroid Build Coastguard Worker
4401*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_CONSOLE_LOGS, NULL, 0,
4402*4f2df630SAndroid Build Coastguard Worker response, &response_size);
4403*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4404*4f2df630SAndroid Build Coastguard Worker printf("Get console logs failed. (%X)\n", rv);
4405*4f2df630SAndroid Build Coastguard Worker return 1;
4406*4f2df630SAndroid Build Coastguard Worker }
4407*4f2df630SAndroid Build Coastguard Worker
4408*4f2df630SAndroid Build Coastguard Worker printf("%s", response);
4409*4f2df630SAndroid Build Coastguard Worker printf("\n");
4410*4f2df630SAndroid Build Coastguard Worker return 0;
4411*4f2df630SAndroid Build Coastguard Worker }
4412*4f2df630SAndroid Build Coastguard Worker
process_get_factory_config(struct transfer_descriptor * td)4413*4f2df630SAndroid Build Coastguard Worker static int process_get_factory_config(struct transfer_descriptor *td)
4414*4f2df630SAndroid Build Coastguard Worker {
4415*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4416*4f2df630SAndroid Build Coastguard Worker uint64_t response = 0;
4417*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4418*4f2df630SAndroid Build Coastguard Worker
4419*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_FACTORY_CONFIG, NULL, 0,
4420*4f2df630SAndroid Build Coastguard Worker (uint8_t *)&response, &response_size);
4421*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4422*4f2df630SAndroid Build Coastguard Worker printf("Get factory config failed. (%X)\n", rv);
4423*4f2df630SAndroid Build Coastguard Worker return 1;
4424*4f2df630SAndroid Build Coastguard Worker }
4425*4f2df630SAndroid Build Coastguard Worker
4426*4f2df630SAndroid Build Coastguard Worker if (response_size < sizeof(uint64_t)) {
4427*4f2df630SAndroid Build Coastguard Worker printf("Unexpected response size. (%zu)", response_size);
4428*4f2df630SAndroid Build Coastguard Worker return 2;
4429*4f2df630SAndroid Build Coastguard Worker }
4430*4f2df630SAndroid Build Coastguard Worker
4431*4f2df630SAndroid Build Coastguard Worker uint64_t out = be64toh(response);
4432*4f2df630SAndroid Build Coastguard Worker bool is_x_branded = (out >> 4) & 1;
4433*4f2df630SAndroid Build Coastguard Worker uint8_t compliance_version = out & 0xF;
4434*4f2df630SAndroid Build Coastguard Worker
4435*4f2df630SAndroid Build Coastguard Worker printf("raw value: %016" PRIX64 "\n", out);
4436*4f2df630SAndroid Build Coastguard Worker printf("chassis_x_branded: %s\n", is_x_branded ? "true" : "false");
4437*4f2df630SAndroid Build Coastguard Worker printf("hw_x_compliance_version: %02X\n", compliance_version);
4438*4f2df630SAndroid Build Coastguard Worker return 0;
4439*4f2df630SAndroid Build Coastguard Worker }
4440*4f2df630SAndroid Build Coastguard Worker
process_set_factory_config(struct transfer_descriptor * td,uint64_t val)4441*4f2df630SAndroid Build Coastguard Worker static int process_set_factory_config(struct transfer_descriptor *td,
4442*4f2df630SAndroid Build Coastguard Worker uint64_t val)
4443*4f2df630SAndroid Build Coastguard Worker {
4444*4f2df630SAndroid Build Coastguard Worker uint64_t val_be = htobe64(val);
4445*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4446*4f2df630SAndroid Build Coastguard Worker
4447*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_SET_FACTORY_CONFIG, &val_be,
4448*4f2df630SAndroid Build Coastguard Worker sizeof(val_be), NULL, NULL);
4449*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4450*4f2df630SAndroid Build Coastguard Worker printf("Factory config failed. (%X)\n", rv);
4451*4f2df630SAndroid Build Coastguard Worker return 1;
4452*4f2df630SAndroid Build Coastguard Worker }
4453*4f2df630SAndroid Build Coastguard Worker
4454*4f2df630SAndroid Build Coastguard Worker return 0;
4455*4f2df630SAndroid Build Coastguard Worker }
4456*4f2df630SAndroid Build Coastguard Worker
process_get_time(struct transfer_descriptor * td)4457*4f2df630SAndroid Build Coastguard Worker static int process_get_time(struct transfer_descriptor *td)
4458*4f2df630SAndroid Build Coastguard Worker {
4459*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4460*4f2df630SAndroid Build Coastguard Worker uint64_t response = 0;
4461*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4462*4f2df630SAndroid Build Coastguard Worker
4463*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_TIME, NULL, 0,
4464*4f2df630SAndroid Build Coastguard Worker (uint8_t *)&response, &response_size);
4465*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4466*4f2df630SAndroid Build Coastguard Worker printf("Get time failed. (%X)\n", rv);
4467*4f2df630SAndroid Build Coastguard Worker return 1;
4468*4f2df630SAndroid Build Coastguard Worker }
4469*4f2df630SAndroid Build Coastguard Worker
4470*4f2df630SAndroid Build Coastguard Worker if (response_size < sizeof(uint64_t)) {
4471*4f2df630SAndroid Build Coastguard Worker printf("Unexpected response size. (%zu)", response_size);
4472*4f2df630SAndroid Build Coastguard Worker return 2;
4473*4f2df630SAndroid Build Coastguard Worker }
4474*4f2df630SAndroid Build Coastguard Worker
4475*4f2df630SAndroid Build Coastguard Worker uint64_t out = be64toh(response);
4476*4f2df630SAndroid Build Coastguard Worker
4477*4f2df630SAndroid Build Coastguard Worker printf("%" PRIu64 "\n", out);
4478*4f2df630SAndroid Build Coastguard Worker return 0;
4479*4f2df630SAndroid Build Coastguard Worker }
4480*4f2df630SAndroid Build Coastguard Worker
print_ti50_misc_status(uint32_t misc_status,uint32_t version)4481*4f2df630SAndroid Build Coastguard Worker static void print_ti50_misc_status(uint32_t misc_status, uint32_t version)
4482*4f2df630SAndroid Build Coastguard Worker {
4483*4f2df630SAndroid Build Coastguard Worker misc_status = be32toh(misc_status);
4484*4f2df630SAndroid Build Coastguard Worker printf("misc_status (%d): %08x\n", version, misc_status);
4485*4f2df630SAndroid Build Coastguard Worker printf(" rdd_keepalive: %d\n",
4486*4f2df630SAndroid Build Coastguard Worker misc_status & METRICSV_RDD_KEEP_ALIVE_MASK);
4487*4f2df630SAndroid Build Coastguard Worker printf(" rdd_keepalive_at_boot: %d\n",
4488*4f2df630SAndroid Build Coastguard Worker (misc_status & METRICSV_RDD_KEEP_ALIVE_AT_BOOT_MASK) >>
4489*4f2df630SAndroid Build Coastguard Worker METRICSV_RDD_KEEP_ALIVE_AT_BOOT_SHIFT);
4490*4f2df630SAndroid Build Coastguard Worker printf(" ccd_mode: %d\n",
4491*4f2df630SAndroid Build Coastguard Worker (misc_status & METRICSV_CCD_MODE_MASK) >>
4492*4f2df630SAndroid Build Coastguard Worker METRICSV_CCD_MODE_SHIFT);
4493*4f2df630SAndroid Build Coastguard Worker if (version < 3)
4494*4f2df630SAndroid Build Coastguard Worker return;
4495*4f2df630SAndroid Build Coastguard Worker /* Display metrics added in version 3 */
4496*4f2df630SAndroid Build Coastguard Worker printf(" wp_asserted: %d\n",
4497*4f2df630SAndroid Build Coastguard Worker (misc_status & METRICSV_WP_ASSERTED_MASK) >>
4498*4f2df630SAndroid Build Coastguard Worker METRICSV_WP_ASSERTED_SHIFT);
4499*4f2df630SAndroid Build Coastguard Worker printf(" allow_unverified_ro: %d\n",
4500*4f2df630SAndroid Build Coastguard Worker (misc_status & METRICSV_ALLOW_UNVERIFIED_RO_MASK) >>
4501*4f2df630SAndroid Build Coastguard Worker METRICSV_ALLOW_UNVERIFIED_RO_SHIFT);
4502*4f2df630SAndroid Build Coastguard Worker printf(" is_prod: %d\n",
4503*4f2df630SAndroid Build Coastguard Worker (misc_status & METRICSV_IS_PROD_MASK) >> METRICSV_IS_PROD_SHIFT);
4504*4f2df630SAndroid Build Coastguard Worker }
4505*4f2df630SAndroid Build Coastguard Worker
print_ti50_stats(struct ti50_stats_v0 * stats_v0,size_t size)4506*4f2df630SAndroid Build Coastguard Worker static int print_ti50_stats(struct ti50_stats_v0 *stats_v0, size_t size)
4507*4f2df630SAndroid Build Coastguard Worker {
4508*4f2df630SAndroid Build Coastguard Worker stats_v0->fs_init_time = be32toh(stats_v0->fs_init_time);
4509*4f2df630SAndroid Build Coastguard Worker stats_v0->fs_usage = be32toh(stats_v0->fs_usage);
4510*4f2df630SAndroid Build Coastguard Worker stats_v0->aprov_time = be32toh(stats_v0->aprov_time);
4511*4f2df630SAndroid Build Coastguard Worker stats_v0->expanded_aprov_status =
4512*4f2df630SAndroid Build Coastguard Worker be32toh(stats_v0->expanded_aprov_status);
4513*4f2df630SAndroid Build Coastguard Worker
4514*4f2df630SAndroid Build Coastguard Worker printf("fs_init_time: %d\n", stats_v0->fs_init_time);
4515*4f2df630SAndroid Build Coastguard Worker printf("fs_usage: %d\n", stats_v0->fs_usage);
4516*4f2df630SAndroid Build Coastguard Worker printf("aprov_time: %d\n", stats_v0->aprov_time);
4517*4f2df630SAndroid Build Coastguard Worker printf("expanded_aprov_status: %X\n", stats_v0->expanded_aprov_status);
4518*4f2df630SAndroid Build Coastguard Worker
4519*4f2df630SAndroid Build Coastguard Worker if (size == sizeof(struct ti50_stats_v1)) {
4520*4f2df630SAndroid Build Coastguard Worker struct ti50_stats_v1 *stats_v1 =
4521*4f2df630SAndroid Build Coastguard Worker (struct ti50_stats_v1 *)stats_v0;
4522*4f2df630SAndroid Build Coastguard Worker print_ti50_misc_status(stats_v1->misc_status, 1);
4523*4f2df630SAndroid Build Coastguard Worker return 0;
4524*4f2df630SAndroid Build Coastguard Worker }
4525*4f2df630SAndroid Build Coastguard Worker if (size >= sizeof(struct ti50_stats)) {
4526*4f2df630SAndroid Build Coastguard Worker struct ti50_stats *stats = (struct ti50_stats *)stats_v0;
4527*4f2df630SAndroid Build Coastguard Worker
4528*4f2df630SAndroid Build Coastguard Worker stats->version = be32toh(stats->version);
4529*4f2df630SAndroid Build Coastguard Worker /* Version was added with v2 and therefore must be >= 2. */
4530*4f2df630SAndroid Build Coastguard Worker if (stats->version < 2) {
4531*4f2df630SAndroid Build Coastguard Worker printf("Invalid stats version %d.", stats->version);
4532*4f2df630SAndroid Build Coastguard Worker return 1;
4533*4f2df630SAndroid Build Coastguard Worker }
4534*4f2df630SAndroid Build Coastguard Worker
4535*4f2df630SAndroid Build Coastguard Worker stats->filesystem_busy_count =
4536*4f2df630SAndroid Build Coastguard Worker be32toh(stats->filesystem_busy_count);
4537*4f2df630SAndroid Build Coastguard Worker stats->crypto_busy_count = be32toh(stats->crypto_busy_count);
4538*4f2df630SAndroid Build Coastguard Worker stats->dispatcher_busy_count =
4539*4f2df630SAndroid Build Coastguard Worker be32toh(stats->dispatcher_busy_count);
4540*4f2df630SAndroid Build Coastguard Worker stats->timeslices_expired = be32toh(stats->timeslices_expired);
4541*4f2df630SAndroid Build Coastguard Worker stats->crypto_init_time = be32toh(stats->crypto_init_time);
4542*4f2df630SAndroid Build Coastguard Worker
4543*4f2df630SAndroid Build Coastguard Worker printf("filesystem_busy_count: %d\n",
4544*4f2df630SAndroid Build Coastguard Worker stats->filesystem_busy_count);
4545*4f2df630SAndroid Build Coastguard Worker printf("crypto_busy_count: %d\n", stats->crypto_busy_count);
4546*4f2df630SAndroid Build Coastguard Worker printf("dispatcher_busy_count: %d\n",
4547*4f2df630SAndroid Build Coastguard Worker stats->dispatcher_busy_count);
4548*4f2df630SAndroid Build Coastguard Worker printf("timeslices_expired: %d\n",
4549*4f2df630SAndroid Build Coastguard Worker stats->timeslices_expired);
4550*4f2df630SAndroid Build Coastguard Worker printf("crypto_init_time: %d\n", stats->crypto_init_time);
4551*4f2df630SAndroid Build Coastguard Worker print_ti50_misc_status(stats->v1.misc_status, stats->version);
4552*4f2df630SAndroid Build Coastguard Worker }
4553*4f2df630SAndroid Build Coastguard Worker return 0;
4554*4f2df630SAndroid Build Coastguard Worker }
4555*4f2df630SAndroid Build Coastguard Worker
process_ti50_get_metrics(struct transfer_descriptor * td,bool show_machine_output)4556*4f2df630SAndroid Build Coastguard Worker static int process_ti50_get_metrics(struct transfer_descriptor *td,
4557*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
4558*4f2df630SAndroid Build Coastguard Worker {
4559*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4560*4f2df630SAndroid Build Coastguard Worker /* Allocate extra space in case future versions add more data. */
4561*4f2df630SAndroid Build Coastguard Worker struct ti50_stats response[4];
4562*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4563*4f2df630SAndroid Build Coastguard Worker
4564*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_TI50_STATS, NULL, 0,
4565*4f2df630SAndroid Build Coastguard Worker (uint8_t *)&response, &response_size);
4566*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4567*4f2df630SAndroid Build Coastguard Worker printf("Get stats failed. (%X)\n", rv);
4568*4f2df630SAndroid Build Coastguard Worker return 1;
4569*4f2df630SAndroid Build Coastguard Worker }
4570*4f2df630SAndroid Build Coastguard Worker
4571*4f2df630SAndroid Build Coastguard Worker if (response_size < sizeof(struct ti50_stats_v0)) {
4572*4f2df630SAndroid Build Coastguard Worker printf("Unexpected response size. (%zu)\n", response_size);
4573*4f2df630SAndroid Build Coastguard Worker return 2;
4574*4f2df630SAndroid Build Coastguard Worker }
4575*4f2df630SAndroid Build Coastguard Worker
4576*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
4577*4f2df630SAndroid Build Coastguard Worker uint8_t *raw_response = (uint8_t *)response;
4578*4f2df630SAndroid Build Coastguard Worker
4579*4f2df630SAndroid Build Coastguard Worker for (size_t i = 0; i < response_size; i++)
4580*4f2df630SAndroid Build Coastguard Worker printf("%02X", raw_response[i]);
4581*4f2df630SAndroid Build Coastguard Worker } else {
4582*4f2df630SAndroid Build Coastguard Worker return print_ti50_stats((struct ti50_stats_v0 *)response,
4583*4f2df630SAndroid Build Coastguard Worker response_size);
4584*4f2df630SAndroid Build Coastguard Worker }
4585*4f2df630SAndroid Build Coastguard Worker return 0;
4586*4f2df630SAndroid Build Coastguard Worker }
4587*4f2df630SAndroid Build Coastguard Worker
process_cr50_get_metrics(struct transfer_descriptor * td,bool show_machine_output)4588*4f2df630SAndroid Build Coastguard Worker static int process_cr50_get_metrics(struct transfer_descriptor *td,
4589*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
4590*4f2df630SAndroid Build Coastguard Worker {
4591*4f2df630SAndroid Build Coastguard Worker /* Allocate extra space in case future versions add more data. */
4592*4f2df630SAndroid Build Coastguard Worker struct cr50_stats_response response[4] = {};
4593*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4594*4f2df630SAndroid Build Coastguard Worker struct cr50_stats_response stats;
4595*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4596*4f2df630SAndroid Build Coastguard Worker
4597*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_CR50_METRICS, NULL, 0,
4598*4f2df630SAndroid Build Coastguard Worker (uint8_t *)&response, &response_size);
4599*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4600*4f2df630SAndroid Build Coastguard Worker printf("Get stats failed. (%X)\n", rv);
4601*4f2df630SAndroid Build Coastguard Worker return 1;
4602*4f2df630SAndroid Build Coastguard Worker }
4603*4f2df630SAndroid Build Coastguard Worker
4604*4f2df630SAndroid Build Coastguard Worker if (response_size != sizeof(stats)) {
4605*4f2df630SAndroid Build Coastguard Worker printf("Unexpected response size. (%zu)\n", response_size);
4606*4f2df630SAndroid Build Coastguard Worker return 2;
4607*4f2df630SAndroid Build Coastguard Worker }
4608*4f2df630SAndroid Build Coastguard Worker
4609*4f2df630SAndroid Build Coastguard Worker /* Let's check if this is a newer version response. */
4610*4f2df630SAndroid Build Coastguard Worker memcpy(&stats, response, sizeof(stats));
4611*4f2df630SAndroid Build Coastguard Worker
4612*4f2df630SAndroid Build Coastguard Worker stats.version = be32toh(stats.version);
4613*4f2df630SAndroid Build Coastguard Worker stats.reset_src = be32toh(stats.reset_src);
4614*4f2df630SAndroid Build Coastguard Worker stats.brdprop = be32toh(stats.brdprop);
4615*4f2df630SAndroid Build Coastguard Worker stats.reset_time_s = be64toh(stats.reset_time_s);
4616*4f2df630SAndroid Build Coastguard Worker stats.cold_reset_time_s = be32toh(stats.cold_reset_time_s);
4617*4f2df630SAndroid Build Coastguard Worker stats.misc_status = be32toh(stats.misc_status);
4618*4f2df630SAndroid Build Coastguard Worker
4619*4f2df630SAndroid Build Coastguard Worker if (stats.version > CR50_METRICSV_STATS_VERSION) {
4620*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "unsupported ver - %d. supports up to %d\n",
4621*4f2df630SAndroid Build Coastguard Worker stats.version, CR50_METRICSV_STATS_VERSION);
4622*4f2df630SAndroid Build Coastguard Worker }
4623*4f2df630SAndroid Build Coastguard Worker printf("version: %10u\n", stats.version);
4624*4f2df630SAndroid Build Coastguard Worker printf("reset_src: 0x%010x\n", stats.reset_src);
4625*4f2df630SAndroid Build Coastguard Worker printf("brdprop: 0x%010x\n", stats.brdprop);
4626*4f2df630SAndroid Build Coastguard Worker printf("cold_reset_time_s: %10u\n", stats.cold_reset_time_s);
4627*4f2df630SAndroid Build Coastguard Worker printf("reset_time_s: %10u\n", stats.reset_time_s);
4628*4f2df630SAndroid Build Coastguard Worker printf("misc_status: 0x%010x\n", stats.misc_status);
4629*4f2df630SAndroid Build Coastguard Worker
4630*4f2df630SAndroid Build Coastguard Worker printf(" rdd detected: %7d\n",
4631*4f2df630SAndroid Build Coastguard Worker (stats.misc_status >> CR50_METRICSV_RDD_IS_DETECTED_SHIFT) & 1);
4632*4f2df630SAndroid Build Coastguard Worker printf(" rddkeeplive en: %7d\n",
4633*4f2df630SAndroid Build Coastguard Worker (stats.misc_status >> CR50_METRICSV_RDD_KEEPALIVE_EN_SHIFT) & 1);
4634*4f2df630SAndroid Build Coastguard Worker printf(" rddkeeplive en atboot: %3d\n",
4635*4f2df630SAndroid Build Coastguard Worker (stats.misc_status >>
4636*4f2df630SAndroid Build Coastguard Worker CR50_METRICSV_RDD_KEEPALIVE_EN_ATBOOT_SHIFT) &
4637*4f2df630SAndroid Build Coastguard Worker 1);
4638*4f2df630SAndroid Build Coastguard Worker printf(" ccd_mode en: %7d\n",
4639*4f2df630SAndroid Build Coastguard Worker (stats.misc_status >> CR50_METRICSV_CCD_MODE_EN_SHIFT) & 1);
4640*4f2df630SAndroid Build Coastguard Worker printf(" ambigous straps: %7d\n",
4641*4f2df630SAndroid Build Coastguard Worker (stats.misc_status >> CR50_METRICSV_AMBIGUOUS_STRAP_SHIFT) & 1);
4642*4f2df630SAndroid Build Coastguard Worker
4643*4f2df630SAndroid Build Coastguard Worker return 0;
4644*4f2df630SAndroid Build Coastguard Worker }
4645*4f2df630SAndroid Build Coastguard Worker
4646*4f2df630SAndroid Build Coastguard Worker /*
4647*4f2df630SAndroid Build Coastguard Worker * The below variables and array must be held in sync with the appropriate
4648*4f2df630SAndroid Build Coastguard Worker * counterparts in defined in ti50:common/{hil,capsules}/src/boot_tracer.rs.
4649*4f2df630SAndroid Build Coastguard Worker */
4650*4f2df630SAndroid Build Coastguard Worker #define MAX_BOOT_TRACE_SIZE 54
4651*4f2df630SAndroid Build Coastguard Worker #define TIMESPAN_EVENT 0
4652*4f2df630SAndroid Build Coastguard Worker #define TIME_SHIFT 11
4653*4f2df630SAndroid Build Coastguard Worker #define MAX_TIME_MS (1 << TIME_SHIFT)
4654*4f2df630SAndroid Build Coastguard Worker static const char *const boot_tracer_stages[] = {
4655*4f2df630SAndroid Build Coastguard Worker "Timespan", /* This one will not be displayed separately. */
4656*4f2df630SAndroid Build Coastguard Worker "ProjectStart", "EcRstAsserted", "EcRstDeasserted",
4657*4f2df630SAndroid Build Coastguard Worker "TpmRstAsserted", "TpmRstDeasserted", "FirstApComms",
4658*4f2df630SAndroid Build Coastguard Worker "PcrExtension", "TpmAppReady"
4659*4f2df630SAndroid Build Coastguard Worker };
4660*4f2df630SAndroid Build Coastguard Worker
process_get_boot_trace(struct transfer_descriptor * td,bool erase,bool show_machine_output)4661*4f2df630SAndroid Build Coastguard Worker static int process_get_boot_trace(struct transfer_descriptor *td, bool erase,
4662*4f2df630SAndroid Build Coastguard Worker bool show_machine_output)
4663*4f2df630SAndroid Build Coastguard Worker {
4664*4f2df630SAndroid Build Coastguard Worker /* zero means no erase, 1 means erase. */
4665*4f2df630SAndroid Build Coastguard Worker uint32_t payload = htobe32(erase);
4666*4f2df630SAndroid Build Coastguard Worker uint16_t boot_trace[MAX_BOOT_TRACE_SIZE / sizeof(uint16_t)];
4667*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(boot_trace);
4668*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4669*4f2df630SAndroid Build Coastguard Worker uint64_t timespan = 0;
4670*4f2df630SAndroid Build Coastguard Worker size_t i;
4671*4f2df630SAndroid Build Coastguard Worker
4672*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_BOOT_TRACE, &payload,
4673*4f2df630SAndroid Build Coastguard Worker sizeof(payload), &boot_trace, &response_size);
4674*4f2df630SAndroid Build Coastguard Worker
4675*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4676*4f2df630SAndroid Build Coastguard Worker printf("Get boot trace failed. (%X)\n", rv);
4677*4f2df630SAndroid Build Coastguard Worker return 1;
4678*4f2df630SAndroid Build Coastguard Worker }
4679*4f2df630SAndroid Build Coastguard Worker
4680*4f2df630SAndroid Build Coastguard Worker if (response_size == 0)
4681*4f2df630SAndroid Build Coastguard Worker return 0; /* Trace is empty. */
4682*4f2df630SAndroid Build Coastguard Worker
4683*4f2df630SAndroid Build Coastguard Worker if (!show_machine_output)
4684*4f2df630SAndroid Build Coastguard Worker printf(" got %zd bytes back:\n", response_size);
4685*4f2df630SAndroid Build Coastguard Worker if (response_size > 0) {
4686*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < response_size / sizeof(uint16_t); i++) {
4687*4f2df630SAndroid Build Coastguard Worker uint16_t entry = boot_trace[i];
4688*4f2df630SAndroid Build Coastguard Worker uint16_t event_id = entry >> TIME_SHIFT;
4689*4f2df630SAndroid Build Coastguard Worker uint16_t delta_time = entry & ((1 << TIME_SHIFT) - 1);
4690*4f2df630SAndroid Build Coastguard Worker
4691*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
4692*4f2df630SAndroid Build Coastguard Worker printf(" %04x", entry);
4693*4f2df630SAndroid Build Coastguard Worker continue;
4694*4f2df630SAndroid Build Coastguard Worker }
4695*4f2df630SAndroid Build Coastguard Worker
4696*4f2df630SAndroid Build Coastguard Worker if (event_id >= ARRAY_SIZE(boot_tracer_stages)) {
4697*4f2df630SAndroid Build Coastguard Worker printf("Unknown event %d\n", event_id);
4698*4f2df630SAndroid Build Coastguard Worker continue;
4699*4f2df630SAndroid Build Coastguard Worker }
4700*4f2df630SAndroid Build Coastguard Worker
4701*4f2df630SAndroid Build Coastguard Worker if (event_id == TIMESPAN_EVENT) {
4702*4f2df630SAndroid Build Coastguard Worker timespan += (uint64_t)delta_time * MAX_TIME_MS;
4703*4f2df630SAndroid Build Coastguard Worker continue;
4704*4f2df630SAndroid Build Coastguard Worker }
4705*4f2df630SAndroid Build Coastguard Worker printf(" %20s: %4" PRId64 " ms\n",
4706*4f2df630SAndroid Build Coastguard Worker boot_tracer_stages[event_id],
4707*4f2df630SAndroid Build Coastguard Worker timespan + delta_time);
4708*4f2df630SAndroid Build Coastguard Worker timespan = 0;
4709*4f2df630SAndroid Build Coastguard Worker }
4710*4f2df630SAndroid Build Coastguard Worker printf("\n");
4711*4f2df630SAndroid Build Coastguard Worker }
4712*4f2df630SAndroid Build Coastguard Worker return 0;
4713*4f2df630SAndroid Build Coastguard Worker }
4714*4f2df630SAndroid Build Coastguard Worker
4715*4f2df630SAndroid Build Coastguard Worker struct get_chip_id_response {
4716*4f2df630SAndroid Build Coastguard Worker uint32_t tpm_vid_pid;
4717*4f2df630SAndroid Build Coastguard Worker uint32_t chip_id;
4718*4f2df630SAndroid Build Coastguard Worker };
4719*4f2df630SAndroid Build Coastguard Worker
get_chip_id_info(struct transfer_descriptor * td)4720*4f2df630SAndroid Build Coastguard Worker static struct get_chip_id_response get_chip_id_info(
4721*4f2df630SAndroid Build Coastguard Worker struct transfer_descriptor *td)
4722*4f2df630SAndroid Build Coastguard Worker {
4723*4f2df630SAndroid Build Coastguard Worker uint32_t rv;
4724*4f2df630SAndroid Build Coastguard Worker struct get_chip_id_response response;
4725*4f2df630SAndroid Build Coastguard Worker size_t response_size = sizeof(response);
4726*4f2df630SAndroid Build Coastguard Worker
4727*4f2df630SAndroid Build Coastguard Worker rv = send_vendor_command(td, VENDOR_CC_GET_CHIP_ID, NULL, 0,
4728*4f2df630SAndroid Build Coastguard Worker (uint8_t *)&response, &response_size);
4729*4f2df630SAndroid Build Coastguard Worker if (rv != VENDOR_RC_SUCCESS) {
4730*4f2df630SAndroid Build Coastguard Worker debug("Failed getting chip id: 0x%X. Okay for older chips\n",
4731*4f2df630SAndroid Build Coastguard Worker rv);
4732*4f2df630SAndroid Build Coastguard Worker } else if (response_size < sizeof(response)) {
4733*4f2df630SAndroid Build Coastguard Worker debug("Unexpected response size. (%zu)\n", response_size);
4734*4f2df630SAndroid Build Coastguard Worker } else {
4735*4f2df630SAndroid Build Coastguard Worker /* Success, convert endianness then return */
4736*4f2df630SAndroid Build Coastguard Worker response.tpm_vid_pid = be32toh(response.tpm_vid_pid);
4737*4f2df630SAndroid Build Coastguard Worker response.chip_id = be32toh(response.chip_id);
4738*4f2df630SAndroid Build Coastguard Worker return response;
4739*4f2df630SAndroid Build Coastguard Worker }
4740*4f2df630SAndroid Build Coastguard Worker /* Zero memory before returning since there was an error */
4741*4f2df630SAndroid Build Coastguard Worker memset(&response, 0, sizeof(response));
4742*4f2df630SAndroid Build Coastguard Worker return response;
4743*4f2df630SAndroid Build Coastguard Worker }
4744*4f2df630SAndroid Build Coastguard Worker
4745*4f2df630SAndroid Build Coastguard Worker /*
4746*4f2df630SAndroid Build Coastguard Worker * Returns the GSC device type determine by how is responds to TPMV and
4747*4f2df630SAndroid Build Coastguard Worker * version requests.
4748*4f2df630SAndroid Build Coastguard Worker */
determine_gsc_type(struct transfer_descriptor * td)4749*4f2df630SAndroid Build Coastguard Worker static enum gsc_device determine_gsc_type(struct transfer_descriptor *td)
4750*4f2df630SAndroid Build Coastguard Worker {
4751*4f2df630SAndroid Build Coastguard Worker int epoch;
4752*4f2df630SAndroid Build Coastguard Worker int major;
4753*4f2df630SAndroid Build Coastguard Worker struct get_chip_id_response chip_id;
4754*4f2df630SAndroid Build Coastguard Worker
4755*4f2df630SAndroid Build Coastguard Worker /*
4756*4f2df630SAndroid Build Coastguard Worker * Get the firmware version first. See if this is a specific GSC version
4757*4f2df630SAndroid Build Coastguard Worker * where the Ti50 FW does not response with an error code if the host
4758*4f2df630SAndroid Build Coastguard Worker * tries an unknown TPMV command over USB. This prevents a USB timeout
4759*4f2df630SAndroid Build Coastguard Worker * and shutting down of USB subsystem within gsctool (b/368631328).
4760*4f2df630SAndroid Build Coastguard Worker */
4761*4f2df630SAndroid Build Coastguard Worker get_version(td, false);
4762*4f2df630SAndroid Build Coastguard Worker epoch = targ.shv[1].epoch;
4763*4f2df630SAndroid Build Coastguard Worker major = targ.shv[1].major;
4764*4f2df630SAndroid Build Coastguard Worker if ((epoch == 0 || epoch == 1) && (major >= 21 && major <= 26))
4765*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_DT;
4766*4f2df630SAndroid Build Coastguard Worker /*
4767*4f2df630SAndroid Build Coastguard Worker * Try the newer TPMV command. If the command isn't supported,
4768*4f2df630SAndroid Build Coastguard Worker * then the GSC should respond with an error. If that happens we will
4769*4f2df630SAndroid Build Coastguard Worker * fall back to the GSC version as the indicator.
4770*4f2df630SAndroid Build Coastguard Worker */
4771*4f2df630SAndroid Build Coastguard Worker chip_id = get_chip_id_info(td);
4772*4f2df630SAndroid Build Coastguard Worker switch (chip_id.tpm_vid_pid) {
4773*4f2df630SAndroid Build Coastguard Worker case 0x50666666:
4774*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_NT;
4775*4f2df630SAndroid Build Coastguard Worker case 0x504a6666:
4776*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_DT;
4777*4f2df630SAndroid Build Coastguard Worker case 0x00281ae0:
4778*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_H1;
4779*4f2df630SAndroid Build Coastguard Worker }
4780*4f2df630SAndroid Build Coastguard Worker
4781*4f2df630SAndroid Build Coastguard Worker if (chip_id.tpm_vid_pid)
4782*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unregonized VID_PID 0x%X\n",
4783*4f2df630SAndroid Build Coastguard Worker chip_id.tpm_vid_pid);
4784*4f2df630SAndroid Build Coastguard Worker
4785*4f2df630SAndroid Build Coastguard Worker /*
4786*4f2df630SAndroid Build Coastguard Worker * If TPMV command doesn't exist or VID_PID is unrecognized then,
4787*4f2df630SAndroid Build Coastguard Worker * use the firmware version to determine type.
4788*4f2df630SAndroid Build Coastguard Worker */
4789*4f2df630SAndroid Build Coastguard Worker major = targ.shv[1].major;
4790*4f2df630SAndroid Build Coastguard Worker if (major >= 30 && major < 40)
4791*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_NT;
4792*4f2df630SAndroid Build Coastguard Worker else if (major >= 20 && major < 30)
4793*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_DT;
4794*4f2df630SAndroid Build Coastguard Worker else
4795*4f2df630SAndroid Build Coastguard Worker return GSC_DEVICE_H1;
4796*4f2df630SAndroid Build Coastguard Worker }
4797*4f2df630SAndroid Build Coastguard Worker
main(int argc,char * argv[])4798*4f2df630SAndroid Build Coastguard Worker int main(int argc, char *argv[])
4799*4f2df630SAndroid Build Coastguard Worker {
4800*4f2df630SAndroid Build Coastguard Worker struct transfer_descriptor td;
4801*4f2df630SAndroid Build Coastguard Worker int rv = 0;
4802*4f2df630SAndroid Build Coastguard Worker int errorcnt;
4803*4f2df630SAndroid Build Coastguard Worker struct image *images = NULL;
4804*4f2df630SAndroid Build Coastguard Worker int num_images = 0;
4805*4f2df630SAndroid Build Coastguard Worker uint16_t vid = 0;
4806*4f2df630SAndroid Build Coastguard Worker uint16_t pid = 0;
4807*4f2df630SAndroid Build Coastguard Worker int i;
4808*4f2df630SAndroid Build Coastguard Worker int transferred_sections = 0;
4809*4f2df630SAndroid Build Coastguard Worker int binary_vers = 0;
4810*4f2df630SAndroid Build Coastguard Worker int show_fw_ver = 0;
4811*4f2df630SAndroid Build Coastguard Worker int rma = 0;
4812*4f2df630SAndroid Build Coastguard Worker const char *rma_auth_code = "";
4813*4f2df630SAndroid Build Coastguard Worker int get_endorsement_seed = 0;
4814*4f2df630SAndroid Build Coastguard Worker const char *endorsement_seed_str = "";
4815*4f2df630SAndroid Build Coastguard Worker int corrupt_inactive_rw = 0;
4816*4f2df630SAndroid Build Coastguard Worker struct board_id bid;
4817*4f2df630SAndroid Build Coastguard Worker enum board_id_action bid_action;
4818*4f2df630SAndroid Build Coastguard Worker int password = 0;
4819*4f2df630SAndroid Build Coastguard Worker int ccd_open = 0;
4820*4f2df630SAndroid Build Coastguard Worker int ccd_unlock = 0;
4821*4f2df630SAndroid Build Coastguard Worker int ccd_lock = 0;
4822*4f2df630SAndroid Build Coastguard Worker int ccd_info = 0;
4823*4f2df630SAndroid Build Coastguard Worker int get_flog = 0;
4824*4f2df630SAndroid Build Coastguard Worker uint32_t prev_log_entry = 0;
4825*4f2df630SAndroid Build Coastguard Worker enum wp_options wp = WP_NONE;
4826*4f2df630SAndroid Build Coastguard Worker int get_boot_mode = 0;
4827*4f2df630SAndroid Build Coastguard Worker int try_all_transfer = 0;
4828*4f2df630SAndroid Build Coastguard Worker int tpm_mode = 0;
4829*4f2df630SAndroid Build Coastguard Worker int get_apro_hash = 0;
4830*4f2df630SAndroid Build Coastguard Worker int get_apro_boot_status = 0;
4831*4f2df630SAndroid Build Coastguard Worker int start_apro_verify = 0;
4832*4f2df630SAndroid Build Coastguard Worker bool show_machine_output = false;
4833*4f2df630SAndroid Build Coastguard Worker int tstamp = 0;
4834*4f2df630SAndroid Build Coastguard Worker const char *tstamp_arg = NULL;
4835*4f2df630SAndroid Build Coastguard Worker enum arv_config_spi_addr_mode_e arv_config_spi_addr_mode =
4836*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_none;
4837*4f2df630SAndroid Build Coastguard Worker enum arv_config_wpsr_choice_e arv_config_wpsr_choice =
4838*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice_none;
4839*4f2df630SAndroid Build Coastguard Worker struct arv_config_wpds arv_config_wpds = { 0 };
4840*4f2df630SAndroid Build Coastguard Worker
4841*4f2df630SAndroid Build Coastguard Worker const char *exclusive_opt_error =
4842*4f2df630SAndroid Build Coastguard Worker "Options -a, -s and -t are mutually exclusive\n";
4843*4f2df630SAndroid Build Coastguard Worker const char *openbox_desc_file = NULL;
4844*4f2df630SAndroid Build Coastguard Worker int factory_mode = 0;
4845*4f2df630SAndroid Build Coastguard Worker char *factory_mode_arg = "";
4846*4f2df630SAndroid Build Coastguard Worker char *tpm_mode_arg = NULL;
4847*4f2df630SAndroid Build Coastguard Worker char *serial = NULL;
4848*4f2df630SAndroid Build Coastguard Worker int sn_bits = 0;
4849*4f2df630SAndroid Build Coastguard Worker uint8_t sn_bits_arg[SN_BITS_SIZE];
4850*4f2df630SAndroid Build Coastguard Worker int sn_inc_rma = 0;
4851*4f2df630SAndroid Build Coastguard Worker uint8_t sn_inc_rma_arg = 0;
4852*4f2df630SAndroid Build Coastguard Worker int erase_ap_ro_hash = 0;
4853*4f2df630SAndroid Build Coastguard Worker int set_capability = 0;
4854*4f2df630SAndroid Build Coastguard Worker const char *capability_parameter = "";
4855*4f2df630SAndroid Build Coastguard Worker bool reboot_gsc = false;
4856*4f2df630SAndroid Build Coastguard Worker size_t reboot_gsc_timeout = 0;
4857*4f2df630SAndroid Build Coastguard Worker int get_clog = 0;
4858*4f2df630SAndroid Build Coastguard Worker int get_console = 0;
4859*4f2df630SAndroid Build Coastguard Worker int factory_config = 0;
4860*4f2df630SAndroid Build Coastguard Worker int set_factory_config = 0;
4861*4f2df630SAndroid Build Coastguard Worker uint64_t factory_config_arg = 0;
4862*4f2df630SAndroid Build Coastguard Worker int get_time = 0;
4863*4f2df630SAndroid Build Coastguard Worker bool get_boot_trace = false;
4864*4f2df630SAndroid Build Coastguard Worker bool erase_boot_trace = false;
4865*4f2df630SAndroid Build Coastguard Worker bool get_metrics = false;
4866*4f2df630SAndroid Build Coastguard Worker bool get_chassis_open = false;
4867*4f2df630SAndroid Build Coastguard Worker bool get_dev_ids = false;
4868*4f2df630SAndroid Build Coastguard Worker bool get_aprov_reset_counts = false;
4869*4f2df630SAndroid Build Coastguard Worker
4870*4f2df630SAndroid Build Coastguard Worker /*
4871*4f2df630SAndroid Build Coastguard Worker * All options which result in setting a Boolean flag to True, along
4872*4f2df630SAndroid Build Coastguard Worker * with addresses of the flags. Terminated by a zeroed entry.
4873*4f2df630SAndroid Build Coastguard Worker */
4874*4f2df630SAndroid Build Coastguard Worker const struct options_map omap[] = {
4875*4f2df630SAndroid Build Coastguard Worker { 'b', &binary_vers },
4876*4f2df630SAndroid Build Coastguard Worker { 'c', &corrupt_inactive_rw },
4877*4f2df630SAndroid Build Coastguard Worker { 'f', &show_fw_ver },
4878*4f2df630SAndroid Build Coastguard Worker { 'g', &get_boot_mode },
4879*4f2df630SAndroid Build Coastguard Worker { 'H', &erase_ap_ro_hash },
4880*4f2df630SAndroid Build Coastguard Worker { 'k', &ccd_lock },
4881*4f2df630SAndroid Build Coastguard Worker { 'o', &ccd_open },
4882*4f2df630SAndroid Build Coastguard Worker { 'P', &password },
4883*4f2df630SAndroid Build Coastguard Worker { 'p', &td.post_reset },
4884*4f2df630SAndroid Build Coastguard Worker { 'U', &ccd_unlock },
4885*4f2df630SAndroid Build Coastguard Worker { 'u', &td.upstart_mode },
4886*4f2df630SAndroid Build Coastguard Worker { 'V', &verbose_mode },
4887*4f2df630SAndroid Build Coastguard Worker {},
4888*4f2df630SAndroid Build Coastguard Worker };
4889*4f2df630SAndroid Build Coastguard Worker
4890*4f2df630SAndroid Build Coastguard Worker /*
4891*4f2df630SAndroid Build Coastguard Worker * Explicitly sets buffering type to line buffered so that output
4892*4f2df630SAndroid Build Coastguard Worker * lines can be written to pipe instantly. This is needed when the
4893*4f2df630SAndroid Build Coastguard Worker * cr50-verify-ro.sh execution in verify_ro is moved from crosh to
4894*4f2df630SAndroid Build Coastguard Worker * debugd.
4895*4f2df630SAndroid Build Coastguard Worker */
4896*4f2df630SAndroid Build Coastguard Worker setlinebuf(stdout);
4897*4f2df630SAndroid Build Coastguard Worker
4898*4f2df630SAndroid Build Coastguard Worker progname = strrchr(argv[0], '/');
4899*4f2df630SAndroid Build Coastguard Worker if (progname)
4900*4f2df630SAndroid Build Coastguard Worker progname++;
4901*4f2df630SAndroid Build Coastguard Worker else
4902*4f2df630SAndroid Build Coastguard Worker progname = argv[0];
4903*4f2df630SAndroid Build Coastguard Worker
4904*4f2df630SAndroid Build Coastguard Worker /* Usb transfer - default mode. */
4905*4f2df630SAndroid Build Coastguard Worker memset(&td, 0, sizeof(td));
4906*4f2df630SAndroid Build Coastguard Worker td.ep_type = usb_xfer;
4907*4f2df630SAndroid Build Coastguard Worker
4908*4f2df630SAndroid Build Coastguard Worker bid_action = bid_none;
4909*4f2df630SAndroid Build Coastguard Worker errorcnt = 0;
4910*4f2df630SAndroid Build Coastguard Worker opterr = 0; /* quiet, you */
4911*4f2df630SAndroid Build Coastguard Worker
4912*4f2df630SAndroid Build Coastguard Worker while ((i = getopt_all(argc, argv)) != -1) {
4913*4f2df630SAndroid Build Coastguard Worker if (check_boolean(omap, i))
4914*4f2df630SAndroid Build Coastguard Worker continue;
4915*4f2df630SAndroid Build Coastguard Worker switch (i) {
4916*4f2df630SAndroid Build Coastguard Worker case 'A':
4917*4f2df630SAndroid Build Coastguard Worker get_apro_hash = 1;
4918*4f2df630SAndroid Build Coastguard Worker break;
4919*4f2df630SAndroid Build Coastguard Worker case 'a':
4920*4f2df630SAndroid Build Coastguard Worker if (td.ep_type) {
4921*4f2df630SAndroid Build Coastguard Worker errorcnt++;
4922*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "%s", exclusive_opt_error);
4923*4f2df630SAndroid Build Coastguard Worker break;
4924*4f2df630SAndroid Build Coastguard Worker }
4925*4f2df630SAndroid Build Coastguard Worker try_all_transfer = 1;
4926*4f2df630SAndroid Build Coastguard Worker /* Try dev_xfer first. */
4927*4f2df630SAndroid Build Coastguard Worker td.ep_type = dev_xfer;
4928*4f2df630SAndroid Build Coastguard Worker break;
4929*4f2df630SAndroid Build Coastguard Worker case 'B':
4930*4f2df630SAndroid Build Coastguard Worker if (optarg && !strcmp(optarg, "start"))
4931*4f2df630SAndroid Build Coastguard Worker start_apro_verify = 1;
4932*4f2df630SAndroid Build Coastguard Worker else
4933*4f2df630SAndroid Build Coastguard Worker get_apro_boot_status = 1;
4934*4f2df630SAndroid Build Coastguard Worker break;
4935*4f2df630SAndroid Build Coastguard Worker case 'C':
4936*4f2df630SAndroid Build Coastguard Worker if (optarg && !strncmp(optarg, "3byte", strlen(optarg)))
4937*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode =
4938*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_set_3byte;
4939*4f2df630SAndroid Build Coastguard Worker else if (optarg &&
4940*4f2df630SAndroid Build Coastguard Worker !strncmp(optarg, "4byte", strlen(optarg)))
4941*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode =
4942*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_set_4byte;
4943*4f2df630SAndroid Build Coastguard Worker else
4944*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode =
4945*4f2df630SAndroid Build Coastguard Worker arv_config_spi_addr_mode_get;
4946*4f2df630SAndroid Build Coastguard Worker break;
4947*4f2df630SAndroid Build Coastguard Worker case 'D':
4948*4f2df630SAndroid Build Coastguard Worker /* Option is deprecated and igorned */
4949*4f2df630SAndroid Build Coastguard Worker break;
4950*4f2df630SAndroid Build Coastguard Worker case 'd':
4951*4f2df630SAndroid Build Coastguard Worker if (!parse_vidpid(optarg, &vid, &pid)) {
4952*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
4953*4f2df630SAndroid Build Coastguard Worker "Invalid device argument: \"%s\"\n",
4954*4f2df630SAndroid Build Coastguard Worker optarg);
4955*4f2df630SAndroid Build Coastguard Worker errorcnt++;
4956*4f2df630SAndroid Build Coastguard Worker }
4957*4f2df630SAndroid Build Coastguard Worker break;
4958*4f2df630SAndroid Build Coastguard Worker case 'e':
4959*4f2df630SAndroid Build Coastguard Worker get_endorsement_seed = 1;
4960*4f2df630SAndroid Build Coastguard Worker endorsement_seed_str = optarg;
4961*4f2df630SAndroid Build Coastguard Worker break;
4962*4f2df630SAndroid Build Coastguard Worker case 'E':
4963*4f2df630SAndroid Build Coastguard Worker if (!optarg) {
4964*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice =
4965*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice_get;
4966*4f2df630SAndroid Build Coastguard Worker } else if (optarg && strlen(optarg) > 0) {
4967*4f2df630SAndroid Build Coastguard Worker arv_config_wpds.data[0].state =
4968*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_not_present;
4969*4f2df630SAndroid Build Coastguard Worker arv_config_wpds.data[1].state =
4970*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_not_present;
4971*4f2df630SAndroid Build Coastguard Worker arv_config_wpds.data[2].state =
4972*4f2df630SAndroid Build Coastguard Worker arv_config_setting_state_not_present;
4973*4f2df630SAndroid Build Coastguard Worker
4974*4f2df630SAndroid Build Coastguard Worker rv = parse_wpsrs(optarg, &arv_config_wpds);
4975*4f2df630SAndroid Build Coastguard Worker if (rv == 2 || rv == 4 || rv == 6) {
4976*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice =
4977*4f2df630SAndroid Build Coastguard Worker arv_config_wpsr_choice_set;
4978*4f2df630SAndroid Build Coastguard Worker } else {
4979*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
4980*4f2df630SAndroid Build Coastguard Worker "Invalid write protect descriptors "
4981*4f2df630SAndroid Build Coastguard Worker "hex string: \"%s\"\n",
4982*4f2df630SAndroid Build Coastguard Worker optarg);
4983*4f2df630SAndroid Build Coastguard Worker exit(update_error);
4984*4f2df630SAndroid Build Coastguard Worker }
4985*4f2df630SAndroid Build Coastguard Worker } else {
4986*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
4987*4f2df630SAndroid Build Coastguard Worker "Invalid the write protect descriptors "
4988*4f2df630SAndroid Build Coastguard Worker "hex string length\n");
4989*4f2df630SAndroid Build Coastguard Worker exit(update_error);
4990*4f2df630SAndroid Build Coastguard Worker }
4991*4f2df630SAndroid Build Coastguard Worker
4992*4f2df630SAndroid Build Coastguard Worker break;
4993*4f2df630SAndroid Build Coastguard Worker case 'F':
4994*4f2df630SAndroid Build Coastguard Worker factory_mode = 1;
4995*4f2df630SAndroid Build Coastguard Worker factory_mode_arg = optarg;
4996*4f2df630SAndroid Build Coastguard Worker break;
4997*4f2df630SAndroid Build Coastguard Worker case 'G':
4998*4f2df630SAndroid Build Coastguard Worker get_time = 1;
4999*4f2df630SAndroid Build Coastguard Worker break;
5000*4f2df630SAndroid Build Coastguard Worker case 'h':
5001*4f2df630SAndroid Build Coastguard Worker usage(errorcnt);
5002*4f2df630SAndroid Build Coastguard Worker break;
5003*4f2df630SAndroid Build Coastguard Worker case 'I':
5004*4f2df630SAndroid Build Coastguard Worker if (optarg) {
5005*4f2df630SAndroid Build Coastguard Worker set_capability = 1;
5006*4f2df630SAndroid Build Coastguard Worker capability_parameter = optarg;
5007*4f2df630SAndroid Build Coastguard Worker } else {
5008*4f2df630SAndroid Build Coastguard Worker ccd_info = 1;
5009*4f2df630SAndroid Build Coastguard Worker }
5010*4f2df630SAndroid Build Coastguard Worker break;
5011*4f2df630SAndroid Build Coastguard Worker case 'i':
5012*4f2df630SAndroid Build Coastguard Worker if (!parse_bid(optarg, &bid, &bid_action)) {
5013*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5014*4f2df630SAndroid Build Coastguard Worker "Invalid board id argument: \"%s\"\n",
5015*4f2df630SAndroid Build Coastguard Worker optarg);
5016*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5017*4f2df630SAndroid Build Coastguard Worker }
5018*4f2df630SAndroid Build Coastguard Worker break;
5019*4f2df630SAndroid Build Coastguard Worker case 'J':
5020*4f2df630SAndroid Build Coastguard Worker get_boot_trace = true;
5021*4f2df630SAndroid Build Coastguard Worker if (!optarg)
5022*4f2df630SAndroid Build Coastguard Worker break;
5023*4f2df630SAndroid Build Coastguard Worker if (strncasecmp(optarg, "erase", strlen(optarg))) {
5024*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5025*4f2df630SAndroid Build Coastguard Worker "Invalid boot trace argument: "
5026*4f2df630SAndroid Build Coastguard Worker "\"%s\"\n",
5027*4f2df630SAndroid Build Coastguard Worker optarg);
5028*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5029*4f2df630SAndroid Build Coastguard Worker }
5030*4f2df630SAndroid Build Coastguard Worker erase_boot_trace = true;
5031*4f2df630SAndroid Build Coastguard Worker break;
5032*4f2df630SAndroid Build Coastguard Worker case 'K':
5033*4f2df630SAndroid Build Coastguard Worker if (!strncasecmp(optarg, "chassis_open",
5034*4f2df630SAndroid Build Coastguard Worker strlen(optarg))) {
5035*4f2df630SAndroid Build Coastguard Worker get_chassis_open = true;
5036*4f2df630SAndroid Build Coastguard Worker } else if (!strncasecmp(optarg, "dev_ids",
5037*4f2df630SAndroid Build Coastguard Worker strlen(optarg))) {
5038*4f2df630SAndroid Build Coastguard Worker get_dev_ids = true;
5039*4f2df630SAndroid Build Coastguard Worker } else if (!strncasecmp(optarg,
5040*4f2df630SAndroid Build Coastguard Worker "aprov_gsc_reset_counts",
5041*4f2df630SAndroid Build Coastguard Worker strlen(optarg))) {
5042*4f2df630SAndroid Build Coastguard Worker /*
5043*4f2df630SAndroid Build Coastguard Worker * Note: This is a temporary command that allows
5044*4f2df630SAndroid Build Coastguard Worker * us to collect UMA metrics for how many times
5045*4f2df630SAndroid Build Coastguard Worker * the GSC would have been reset due to the AP
5046*4f2df630SAndroid Build Coastguard Worker * RO verification feature.
5047*4f2df630SAndroid Build Coastguard Worker *
5048*4f2df630SAndroid Build Coastguard Worker * Once the feature is rolled out, remove this
5049*4f2df630SAndroid Build Coastguard Worker * command line option. That is also why this
5050*4f2df630SAndroid Build Coastguard Worker * sub-command is not advertised in the help
5051*4f2df630SAndroid Build Coastguard Worker * menu.
5052*4f2df630SAndroid Build Coastguard Worker */
5053*4f2df630SAndroid Build Coastguard Worker get_aprov_reset_counts = true;
5054*4f2df630SAndroid Build Coastguard Worker } else {
5055*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5056*4f2df630SAndroid Build Coastguard Worker "Invalid get_value argument: "
5057*4f2df630SAndroid Build Coastguard Worker "\"%s\"\n",
5058*4f2df630SAndroid Build Coastguard Worker optarg);
5059*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5060*4f2df630SAndroid Build Coastguard Worker }
5061*4f2df630SAndroid Build Coastguard Worker break;
5062*4f2df630SAndroid Build Coastguard Worker case 'L':
5063*4f2df630SAndroid Build Coastguard Worker get_flog = 1;
5064*4f2df630SAndroid Build Coastguard Worker if (optarg)
5065*4f2df630SAndroid Build Coastguard Worker prev_log_entry = strtoul(optarg, NULL, 0);
5066*4f2df630SAndroid Build Coastguard Worker break;
5067*4f2df630SAndroid Build Coastguard Worker case 'l':
5068*4f2df630SAndroid Build Coastguard Worker get_console = 1;
5069*4f2df630SAndroid Build Coastguard Worker break;
5070*4f2df630SAndroid Build Coastguard Worker case 'M':
5071*4f2df630SAndroid Build Coastguard Worker show_machine_output = true;
5072*4f2df630SAndroid Build Coastguard Worker break;
5073*4f2df630SAndroid Build Coastguard Worker case 'm':
5074*4f2df630SAndroid Build Coastguard Worker tpm_mode = 1;
5075*4f2df630SAndroid Build Coastguard Worker tpm_mode_arg = optarg;
5076*4f2df630SAndroid Build Coastguard Worker break;
5077*4f2df630SAndroid Build Coastguard Worker case 'n':
5078*4f2df630SAndroid Build Coastguard Worker serial = optarg;
5079*4f2df630SAndroid Build Coastguard Worker break;
5080*4f2df630SAndroid Build Coastguard Worker case 'O':
5081*4f2df630SAndroid Build Coastguard Worker openbox_desc_file = optarg;
5082*4f2df630SAndroid Build Coastguard Worker break;
5083*4f2df630SAndroid Build Coastguard Worker case 'q':
5084*4f2df630SAndroid Build Coastguard Worker td.force_ro = 1;
5085*4f2df630SAndroid Build Coastguard Worker break;
5086*4f2df630SAndroid Build Coastguard Worker case 'r':
5087*4f2df630SAndroid Build Coastguard Worker rma = 1;
5088*4f2df630SAndroid Build Coastguard Worker rma_auth_code = optarg;
5089*4f2df630SAndroid Build Coastguard Worker break;
5090*4f2df630SAndroid Build Coastguard Worker case 'R':
5091*4f2df630SAndroid Build Coastguard Worker sn_inc_rma = 1;
5092*4f2df630SAndroid Build Coastguard Worker if (!parse_sn_inc_rma(optarg, &sn_inc_rma_arg)) {
5093*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5094*4f2df630SAndroid Build Coastguard Worker "Invalid sn_rma_inc argument: \"%s\"\n",
5095*4f2df630SAndroid Build Coastguard Worker optarg);
5096*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5097*4f2df630SAndroid Build Coastguard Worker }
5098*4f2df630SAndroid Build Coastguard Worker
5099*4f2df630SAndroid Build Coastguard Worker break;
5100*4f2df630SAndroid Build Coastguard Worker case 's':
5101*4f2df630SAndroid Build Coastguard Worker if (td.ep_type || try_all_transfer) {
5102*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5103*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "%s", exclusive_opt_error);
5104*4f2df630SAndroid Build Coastguard Worker break;
5105*4f2df630SAndroid Build Coastguard Worker }
5106*4f2df630SAndroid Build Coastguard Worker td.ep_type = dev_xfer;
5107*4f2df630SAndroid Build Coastguard Worker break;
5108*4f2df630SAndroid Build Coastguard Worker case 'S':
5109*4f2df630SAndroid Build Coastguard Worker sn_bits = 1;
5110*4f2df630SAndroid Build Coastguard Worker if (!parse_sn_bits(optarg, sn_bits_arg)) {
5111*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5112*4f2df630SAndroid Build Coastguard Worker "Invalid sn_bits argument: \"%s\"\n",
5113*4f2df630SAndroid Build Coastguard Worker optarg);
5114*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5115*4f2df630SAndroid Build Coastguard Worker }
5116*4f2df630SAndroid Build Coastguard Worker
5117*4f2df630SAndroid Build Coastguard Worker break;
5118*4f2df630SAndroid Build Coastguard Worker case 't':
5119*4f2df630SAndroid Build Coastguard Worker if (td.ep_type || try_all_transfer) {
5120*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5121*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "%s", exclusive_opt_error);
5122*4f2df630SAndroid Build Coastguard Worker break;
5123*4f2df630SAndroid Build Coastguard Worker }
5124*4f2df630SAndroid Build Coastguard Worker td.ep_type = ts_xfer;
5125*4f2df630SAndroid Build Coastguard Worker break;
5126*4f2df630SAndroid Build Coastguard Worker case 'T':
5127*4f2df630SAndroid Build Coastguard Worker tstamp = 1;
5128*4f2df630SAndroid Build Coastguard Worker tstamp_arg = optarg;
5129*4f2df630SAndroid Build Coastguard Worker break;
5130*4f2df630SAndroid Build Coastguard Worker case 'v':
5131*4f2df630SAndroid Build Coastguard Worker report_version(); /* This will call exit(). */
5132*4f2df630SAndroid Build Coastguard Worker break;
5133*4f2df630SAndroid Build Coastguard Worker case 'W':
5134*4f2df630SAndroid Build Coastguard Worker get_metrics = true;
5135*4f2df630SAndroid Build Coastguard Worker break;
5136*4f2df630SAndroid Build Coastguard Worker case 'w':
5137*4f2df630SAndroid Build Coastguard Worker if (!optarg) {
5138*4f2df630SAndroid Build Coastguard Worker wp = WP_CHECK;
5139*4f2df630SAndroid Build Coastguard Worker break;
5140*4f2df630SAndroid Build Coastguard Worker }
5141*4f2df630SAndroid Build Coastguard Worker if (!strcasecmp(optarg, "enable")) {
5142*4f2df630SAndroid Build Coastguard Worker wp = WP_ENABLE;
5143*4f2df630SAndroid Build Coastguard Worker break;
5144*4f2df630SAndroid Build Coastguard Worker }
5145*4f2df630SAndroid Build Coastguard Worker if (!strcasecmp(optarg, "disable")) {
5146*4f2df630SAndroid Build Coastguard Worker wp = WP_DISABLE;
5147*4f2df630SAndroid Build Coastguard Worker break;
5148*4f2df630SAndroid Build Coastguard Worker }
5149*4f2df630SAndroid Build Coastguard Worker if (!strcasecmp(optarg, "follow")) {
5150*4f2df630SAndroid Build Coastguard Worker wp = WP_FOLLOW;
5151*4f2df630SAndroid Build Coastguard Worker break;
5152*4f2df630SAndroid Build Coastguard Worker }
5153*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Illegal wp option \"%s\"\n", optarg);
5154*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5155*4f2df630SAndroid Build Coastguard Worker break;
5156*4f2df630SAndroid Build Coastguard Worker case 'x':
5157*4f2df630SAndroid Build Coastguard Worker get_clog = 1;
5158*4f2df630SAndroid Build Coastguard Worker break;
5159*4f2df630SAndroid Build Coastguard Worker case 'y':
5160*4f2df630SAndroid Build Coastguard Worker factory_config = 1;
5161*4f2df630SAndroid Build Coastguard Worker if (optarg) {
5162*4f2df630SAndroid Build Coastguard Worker set_factory_config = 1;
5163*4f2df630SAndroid Build Coastguard Worker factory_config_arg = strtoull(optarg, NULL, 16);
5164*4f2df630SAndroid Build Coastguard Worker }
5165*4f2df630SAndroid Build Coastguard Worker break;
5166*4f2df630SAndroid Build Coastguard Worker case 'z':
5167*4f2df630SAndroid Build Coastguard Worker reboot_gsc = true;
5168*4f2df630SAndroid Build Coastguard Worker /* Set a 1ms default reboot time to avoid libusb errors
5169*4f2df630SAndroid Build Coastguard Worker * when the GSC resets too quickly.
5170*4f2df630SAndroid Build Coastguard Worker */
5171*4f2df630SAndroid Build Coastguard Worker reboot_gsc_timeout = 1;
5172*4f2df630SAndroid Build Coastguard Worker if (optarg)
5173*4f2df630SAndroid Build Coastguard Worker reboot_gsc_timeout = strtoul(optarg, NULL, 0);
5174*4f2df630SAndroid Build Coastguard Worker break;
5175*4f2df630SAndroid Build Coastguard Worker case 0: /* auto-handled option */
5176*4f2df630SAndroid Build Coastguard Worker break;
5177*4f2df630SAndroid Build Coastguard Worker case '?':
5178*4f2df630SAndroid Build Coastguard Worker if (optopt)
5179*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unrecognized option: -%c\n",
5180*4f2df630SAndroid Build Coastguard Worker optopt);
5181*4f2df630SAndroid Build Coastguard Worker else
5182*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Unrecognized option: %s\n",
5183*4f2df630SAndroid Build Coastguard Worker argv[optind - 1]);
5184*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5185*4f2df630SAndroid Build Coastguard Worker break;
5186*4f2df630SAndroid Build Coastguard Worker case ':':
5187*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Missing argument to %s\n",
5188*4f2df630SAndroid Build Coastguard Worker argv[optind - 1]);
5189*4f2df630SAndroid Build Coastguard Worker errorcnt++;
5190*4f2df630SAndroid Build Coastguard Worker break;
5191*4f2df630SAndroid Build Coastguard Worker default:
5192*4f2df630SAndroid Build Coastguard Worker fprintf(stderr, "Internal error at %s:%d\n", __FILE__,
5193*4f2df630SAndroid Build Coastguard Worker __LINE__);
5194*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5195*4f2df630SAndroid Build Coastguard Worker }
5196*4f2df630SAndroid Build Coastguard Worker }
5197*4f2df630SAndroid Build Coastguard Worker
5198*4f2df630SAndroid Build Coastguard Worker if (errorcnt)
5199*4f2df630SAndroid Build Coastguard Worker usage(errorcnt);
5200*4f2df630SAndroid Build Coastguard Worker
5201*4f2df630SAndroid Build Coastguard Worker if ((bid_action == bid_none) &&
5202*4f2df630SAndroid Build Coastguard Worker (arv_config_spi_addr_mode == arv_config_spi_addr_mode_none) &&
5203*4f2df630SAndroid Build Coastguard Worker (arv_config_wpsr_choice == arv_config_wpsr_choice_none) &&
5204*4f2df630SAndroid Build Coastguard Worker !ccd_info && !ccd_lock && !ccd_open && !ccd_unlock &&
5205*4f2df630SAndroid Build Coastguard Worker !corrupt_inactive_rw && !get_apro_hash && !get_apro_boot_status &&
5206*4f2df630SAndroid Build Coastguard Worker !get_boot_mode && !get_boot_trace && !get_clog && !get_console &&
5207*4f2df630SAndroid Build Coastguard Worker !get_flog && !get_endorsement_seed && !get_metrics && !get_time &&
5208*4f2df630SAndroid Build Coastguard Worker !factory_config && !factory_mode && !erase_ap_ro_hash &&
5209*4f2df630SAndroid Build Coastguard Worker !password && !reboot_gsc && !rma && !set_capability &&
5210*4f2df630SAndroid Build Coastguard Worker !show_fw_ver && !sn_bits && !sn_inc_rma && !start_apro_verify &&
5211*4f2df630SAndroid Build Coastguard Worker !openbox_desc_file && !tstamp && !tpm_mode && (wp == WP_NONE) &&
5212*4f2df630SAndroid Build Coastguard Worker !get_chassis_open && !get_dev_ids && !get_aprov_reset_counts) {
5213*4f2df630SAndroid Build Coastguard Worker num_images = argc - optind;
5214*4f2df630SAndroid Build Coastguard Worker if (num_images <= 0) {
5215*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5216*4f2df630SAndroid Build Coastguard Worker "\nERROR: Missing required <binary image>\n\n");
5217*4f2df630SAndroid Build Coastguard Worker usage(1);
5218*4f2df630SAndroid Build Coastguard Worker }
5219*4f2df630SAndroid Build Coastguard Worker
5220*4f2df630SAndroid Build Coastguard Worker images = malloc(sizeof(struct image) * num_images);
5221*4f2df630SAndroid Build Coastguard Worker
5222*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < num_images; i++) {
5223*4f2df630SAndroid Build Coastguard Worker images[i].data = get_file_or_die(argv[optind + i],
5224*4f2df630SAndroid Build Coastguard Worker &images[i].data_len);
5225*4f2df630SAndroid Build Coastguard Worker images[i].file_path = argv[optind + i];
5226*4f2df630SAndroid Build Coastguard Worker printf("read %zd(%#zx) bytes from %s\n",
5227*4f2df630SAndroid Build Coastguard Worker images[i].data_len, images[i].data_len,
5228*4f2df630SAndroid Build Coastguard Worker images[i].file_path);
5229*4f2df630SAndroid Build Coastguard Worker
5230*4f2df630SAndroid Build Coastguard Worker /* Validate images and locate headers within image */
5231*4f2df630SAndroid Build Coastguard Worker if (!locate_headers(&images[i]))
5232*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5233*4f2df630SAndroid Build Coastguard Worker
5234*4f2df630SAndroid Build Coastguard Worker if (!fetch_header_versions(&images[i]))
5235*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5236*4f2df630SAndroid Build Coastguard Worker
5237*4f2df630SAndroid Build Coastguard Worker if (binary_vers) {
5238*4f2df630SAndroid Build Coastguard Worker int error = show_headers_versions(
5239*4f2df630SAndroid Build Coastguard Worker &images[i], show_machine_output);
5240*4f2df630SAndroid Build Coastguard Worker if (error)
5241*4f2df630SAndroid Build Coastguard Worker exit(error);
5242*4f2df630SAndroid Build Coastguard Worker }
5243*4f2df630SAndroid Build Coastguard Worker }
5244*4f2df630SAndroid Build Coastguard Worker /* If displaying versions, exit now since we're done. */
5245*4f2df630SAndroid Build Coastguard Worker if (binary_vers)
5246*4f2df630SAndroid Build Coastguard Worker exit(0);
5247*4f2df630SAndroid Build Coastguard Worker } else {
5248*4f2df630SAndroid Build Coastguard Worker if (optind < argc)
5249*4f2df630SAndroid Build Coastguard Worker printf("Ignoring binary image %s\n", argv[optind]);
5250*4f2df630SAndroid Build Coastguard Worker }
5251*4f2df630SAndroid Build Coastguard Worker
5252*4f2df630SAndroid Build Coastguard Worker if (((bid_action != bid_none) + !!rma + !!password + !!ccd_open +
5253*4f2df630SAndroid Build Coastguard Worker !!ccd_unlock + !!ccd_lock + !!ccd_info + !!get_flog +
5254*4f2df630SAndroid Build Coastguard Worker !!get_boot_mode + !!openbox_desc_file + !!factory_mode +
5255*4f2df630SAndroid Build Coastguard Worker (wp != WP_NONE) + !!get_endorsement_seed + !!erase_ap_ro_hash +
5256*4f2df630SAndroid Build Coastguard Worker !!set_capability + !!get_clog + !!get_console) > 1) {
5257*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5258*4f2df630SAndroid Build Coastguard Worker "Error: options "
5259*4f2df630SAndroid Build Coastguard Worker "-e, -F, -g, -H, -I, -i, -k, -L, -l, -O, -o, -P, -r,"
5260*4f2df630SAndroid Build Coastguard Worker "-U, -x and -w are mutually exclusive\n");
5261*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5262*4f2df630SAndroid Build Coastguard Worker }
5263*4f2df630SAndroid Build Coastguard Worker
5264*4f2df630SAndroid Build Coastguard Worker if (td.ep_type == usb_xfer) {
5265*4f2df630SAndroid Build Coastguard Worker /* Extra variables only used to prevent 80+ character lines */
5266*4f2df630SAndroid Build Coastguard Worker const uint16_t subclass = USB_SUBCLASS_GOOGLE_CR50;
5267*4f2df630SAndroid Build Coastguard Worker const uint16_t protocol =
5268*4f2df630SAndroid Build Coastguard Worker USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE;
5269*4f2df630SAndroid Build Coastguard Worker uint16_t pids[] = { H1_PID, D2_PID, NT_PID };
5270*4f2df630SAndroid Build Coastguard Worker int pid_count = ARRAY_SIZE(pids);
5271*4f2df630SAndroid Build Coastguard Worker
5272*4f2df630SAndroid Build Coastguard Worker /*
5273*4f2df630SAndroid Build Coastguard Worker * If no usb device information was given, use default vid and
5274*4f2df630SAndroid Build Coastguard Worker * pids to search for GSC devices.
5275*4f2df630SAndroid Build Coastguard Worker */
5276*4f2df630SAndroid Build Coastguard Worker if (!vid)
5277*4f2df630SAndroid Build Coastguard Worker vid = USB_VID_GOOGLE;
5278*4f2df630SAndroid Build Coastguard Worker if (pid) {
5279*4f2df630SAndroid Build Coastguard Worker pids[0] = pid;
5280*4f2df630SAndroid Build Coastguard Worker pid_count = 1;
5281*4f2df630SAndroid Build Coastguard Worker }
5282*4f2df630SAndroid Build Coastguard Worker if (usb_findit(serial, vid, pids, pid_count, subclass, protocol,
5283*4f2df630SAndroid Build Coastguard Worker &td.uep)) {
5284*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5285*4f2df630SAndroid Build Coastguard Worker "ERROR: Cannot find single GSC device\n");
5286*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5287*4f2df630SAndroid Build Coastguard Worker }
5288*4f2df630SAndroid Build Coastguard Worker } else if (td.ep_type == dev_xfer) {
5289*4f2df630SAndroid Build Coastguard Worker td.tpm_fd = open("/dev/tpm0", O_RDWR);
5290*4f2df630SAndroid Build Coastguard Worker if (td.tpm_fd < 0) {
5291*4f2df630SAndroid Build Coastguard Worker if (!try_all_transfer) {
5292*4f2df630SAndroid Build Coastguard Worker perror("Could not open TPM");
5293*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5294*4f2df630SAndroid Build Coastguard Worker }
5295*4f2df630SAndroid Build Coastguard Worker td.ep_type = ts_xfer;
5296*4f2df630SAndroid Build Coastguard Worker }
5297*4f2df630SAndroid Build Coastguard Worker }
5298*4f2df630SAndroid Build Coastguard Worker
5299*4f2df630SAndroid Build Coastguard Worker /* Perform run selection of GSC device now that we have a connection */
5300*4f2df630SAndroid Build Coastguard Worker gsc_dev = determine_gsc_type(&td);
5301*4f2df630SAndroid Build Coastguard Worker
5302*4f2df630SAndroid Build Coastguard Worker if (openbox_desc_file)
5303*4f2df630SAndroid Build Coastguard Worker return verify_ro(&td, openbox_desc_file, show_machine_output);
5304*4f2df630SAndroid Build Coastguard Worker
5305*4f2df630SAndroid Build Coastguard Worker if (ccd_unlock || ccd_open || ccd_lock || ccd_info)
5306*4f2df630SAndroid Build Coastguard Worker process_ccd_state(&td, ccd_unlock, ccd_open, ccd_lock, ccd_info,
5307*4f2df630SAndroid Build Coastguard Worker show_machine_output);
5308*4f2df630SAndroid Build Coastguard Worker
5309*4f2df630SAndroid Build Coastguard Worker if (set_capability)
5310*4f2df630SAndroid Build Coastguard Worker exit(process_set_capabililty(&td, capability_parameter));
5311*4f2df630SAndroid Build Coastguard Worker
5312*4f2df630SAndroid Build Coastguard Worker if (password)
5313*4f2df630SAndroid Build Coastguard Worker process_password(&td);
5314*4f2df630SAndroid Build Coastguard Worker
5315*4f2df630SAndroid Build Coastguard Worker if (bid_action != bid_none)
5316*4f2df630SAndroid Build Coastguard Worker process_bid(&td, bid_action, &bid, show_machine_output);
5317*4f2df630SAndroid Build Coastguard Worker
5318*4f2df630SAndroid Build Coastguard Worker if (get_endorsement_seed)
5319*4f2df630SAndroid Build Coastguard Worker exit(process_endorsement_seed(&td, endorsement_seed_str));
5320*4f2df630SAndroid Build Coastguard Worker
5321*4f2df630SAndroid Build Coastguard Worker if (rma)
5322*4f2df630SAndroid Build Coastguard Worker process_rma(&td, rma_auth_code, show_machine_output);
5323*4f2df630SAndroid Build Coastguard Worker
5324*4f2df630SAndroid Build Coastguard Worker if (factory_mode)
5325*4f2df630SAndroid Build Coastguard Worker process_factory_mode(&td, factory_mode_arg);
5326*4f2df630SAndroid Build Coastguard Worker if (wp != WP_NONE)
5327*4f2df630SAndroid Build Coastguard Worker exit(process_wp(&td, wp));
5328*4f2df630SAndroid Build Coastguard Worker
5329*4f2df630SAndroid Build Coastguard Worker if (get_chassis_open)
5330*4f2df630SAndroid Build Coastguard Worker exit(process_get_chassis_open(&td));
5331*4f2df630SAndroid Build Coastguard Worker
5332*4f2df630SAndroid Build Coastguard Worker if (get_dev_ids)
5333*4f2df630SAndroid Build Coastguard Worker exit(process_get_dev_ids(&td, show_machine_output));
5334*4f2df630SAndroid Build Coastguard Worker
5335*4f2df630SAndroid Build Coastguard Worker if (get_aprov_reset_counts)
5336*4f2df630SAndroid Build Coastguard Worker exit(process_get_aprov_reset_counts(&td));
5337*4f2df630SAndroid Build Coastguard Worker
5338*4f2df630SAndroid Build Coastguard Worker if (corrupt_inactive_rw)
5339*4f2df630SAndroid Build Coastguard Worker invalidate_inactive_rw(&td);
5340*4f2df630SAndroid Build Coastguard Worker
5341*4f2df630SAndroid Build Coastguard Worker if (tpm_mode) {
5342*4f2df630SAndroid Build Coastguard Worker int rv = process_tpm_mode(&td, tpm_mode_arg);
5343*4f2df630SAndroid Build Coastguard Worker
5344*4f2df630SAndroid Build Coastguard Worker exit(rv);
5345*4f2df630SAndroid Build Coastguard Worker }
5346*4f2df630SAndroid Build Coastguard Worker
5347*4f2df630SAndroid Build Coastguard Worker if (tstamp)
5348*4f2df630SAndroid Build Coastguard Worker return process_tstamp(&td, tstamp_arg);
5349*4f2df630SAndroid Build Coastguard Worker
5350*4f2df630SAndroid Build Coastguard Worker if (sn_bits)
5351*4f2df630SAndroid Build Coastguard Worker process_sn_bits(&td, sn_bits_arg);
5352*4f2df630SAndroid Build Coastguard Worker
5353*4f2df630SAndroid Build Coastguard Worker if (sn_inc_rma)
5354*4f2df630SAndroid Build Coastguard Worker process_sn_inc_rma(&td, sn_inc_rma_arg);
5355*4f2df630SAndroid Build Coastguard Worker
5356*4f2df630SAndroid Build Coastguard Worker if (get_apro_hash)
5357*4f2df630SAndroid Build Coastguard Worker exit(process_get_apro_hash(&td));
5358*4f2df630SAndroid Build Coastguard Worker
5359*4f2df630SAndroid Build Coastguard Worker if (get_apro_boot_status)
5360*4f2df630SAndroid Build Coastguard Worker exit(process_get_apro_boot_status(&td));
5361*4f2df630SAndroid Build Coastguard Worker
5362*4f2df630SAndroid Build Coastguard Worker if (start_apro_verify)
5363*4f2df630SAndroid Build Coastguard Worker exit(process_start_apro_verify(&td));
5364*4f2df630SAndroid Build Coastguard Worker
5365*4f2df630SAndroid Build Coastguard Worker if (get_boot_mode)
5366*4f2df630SAndroid Build Coastguard Worker exit(process_get_boot_mode(&td));
5367*4f2df630SAndroid Build Coastguard Worker
5368*4f2df630SAndroid Build Coastguard Worker if (get_flog)
5369*4f2df630SAndroid Build Coastguard Worker process_get_flog(&td, prev_log_entry, show_machine_output);
5370*4f2df630SAndroid Build Coastguard Worker
5371*4f2df630SAndroid Build Coastguard Worker if (erase_ap_ro_hash)
5372*4f2df630SAndroid Build Coastguard Worker process_erase_ap_ro_hash(&td);
5373*4f2df630SAndroid Build Coastguard Worker
5374*4f2df630SAndroid Build Coastguard Worker if (arv_config_spi_addr_mode)
5375*4f2df630SAndroid Build Coastguard Worker exit(process_arv_config_spi_addr_mode(
5376*4f2df630SAndroid Build Coastguard Worker &td, arv_config_spi_addr_mode));
5377*4f2df630SAndroid Build Coastguard Worker
5378*4f2df630SAndroid Build Coastguard Worker if (arv_config_wpsr_choice)
5379*4f2df630SAndroid Build Coastguard Worker exit(process_arv_config_wpds(&td, arv_config_wpsr_choice,
5380*4f2df630SAndroid Build Coastguard Worker &arv_config_wpds));
5381*4f2df630SAndroid Build Coastguard Worker
5382*4f2df630SAndroid Build Coastguard Worker if (reboot_gsc)
5383*4f2df630SAndroid Build Coastguard Worker exit(process_reboot_gsc(&td, reboot_gsc_timeout));
5384*4f2df630SAndroid Build Coastguard Worker
5385*4f2df630SAndroid Build Coastguard Worker if (get_clog)
5386*4f2df630SAndroid Build Coastguard Worker exit(get_crashlog(&td));
5387*4f2df630SAndroid Build Coastguard Worker
5388*4f2df630SAndroid Build Coastguard Worker if (get_console)
5389*4f2df630SAndroid Build Coastguard Worker exit(get_console_logs(&td));
5390*4f2df630SAndroid Build Coastguard Worker
5391*4f2df630SAndroid Build Coastguard Worker if (factory_config) {
5392*4f2df630SAndroid Build Coastguard Worker if (set_factory_config)
5393*4f2df630SAndroid Build Coastguard Worker exit(process_set_factory_config(&td,
5394*4f2df630SAndroid Build Coastguard Worker factory_config_arg));
5395*4f2df630SAndroid Build Coastguard Worker else
5396*4f2df630SAndroid Build Coastguard Worker exit(process_get_factory_config(&td));
5397*4f2df630SAndroid Build Coastguard Worker }
5398*4f2df630SAndroid Build Coastguard Worker
5399*4f2df630SAndroid Build Coastguard Worker if (get_time) {
5400*4f2df630SAndroid Build Coastguard Worker exit(process_get_time(&td));
5401*4f2df630SAndroid Build Coastguard Worker }
5402*4f2df630SAndroid Build Coastguard Worker
5403*4f2df630SAndroid Build Coastguard Worker if (get_boot_trace)
5404*4f2df630SAndroid Build Coastguard Worker exit(process_get_boot_trace(&td, erase_boot_trace,
5405*4f2df630SAndroid Build Coastguard Worker show_machine_output));
5406*4f2df630SAndroid Build Coastguard Worker
5407*4f2df630SAndroid Build Coastguard Worker if (get_metrics) {
5408*4f2df630SAndroid Build Coastguard Worker if (is_ti50_device())
5409*4f2df630SAndroid Build Coastguard Worker exit(process_ti50_get_metrics(&td,
5410*4f2df630SAndroid Build Coastguard Worker show_machine_output));
5411*4f2df630SAndroid Build Coastguard Worker else
5412*4f2df630SAndroid Build Coastguard Worker exit(process_cr50_get_metrics(&td,
5413*4f2df630SAndroid Build Coastguard Worker show_machine_output));
5414*4f2df630SAndroid Build Coastguard Worker }
5415*4f2df630SAndroid Build Coastguard Worker
5416*4f2df630SAndroid Build Coastguard Worker if (images || show_fw_ver) {
5417*4f2df630SAndroid Build Coastguard Worker struct image *match = NULL;
5418*4f2df630SAndroid Build Coastguard Worker
5419*4f2df630SAndroid Build Coastguard Worker /* Find the matching image for the runtime-determined device */
5420*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < num_images; i++) {
5421*4f2df630SAndroid Build Coastguard Worker if (images[i].type == gsc_dev) {
5422*4f2df630SAndroid Build Coastguard Worker if (match) {
5423*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5424*4f2df630SAndroid Build Coastguard Worker "ERROR: Must only specify a "
5425*4f2df630SAndroid Build Coastguard Worker "single image for each chip "
5426*4f2df630SAndroid Build Coastguard Worker "type.\n");
5427*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5428*4f2df630SAndroid Build Coastguard Worker }
5429*4f2df630SAndroid Build Coastguard Worker match = &images[i];
5430*4f2df630SAndroid Build Coastguard Worker }
5431*4f2df630SAndroid Build Coastguard Worker }
5432*4f2df630SAndroid Build Coastguard Worker
5433*4f2df630SAndroid Build Coastguard Worker if (images && !match) {
5434*4f2df630SAndroid Build Coastguard Worker fprintf(stderr,
5435*4f2df630SAndroid Build Coastguard Worker "ERROR: No images matches chip type.\n");
5436*4f2df630SAndroid Build Coastguard Worker exit(update_error);
5437*4f2df630SAndroid Build Coastguard Worker }
5438*4f2df630SAndroid Build Coastguard Worker
5439*4f2df630SAndroid Build Coastguard Worker setup_connection(&td);
5440*4f2df630SAndroid Build Coastguard Worker
5441*4f2df630SAndroid Build Coastguard Worker if (match) {
5442*4f2df630SAndroid Build Coastguard Worker if (num_images > 1) {
5443*4f2df630SAndroid Build Coastguard Worker printf("Using file for update: %s\n",
5444*4f2df630SAndroid Build Coastguard Worker match->file_path);
5445*4f2df630SAndroid Build Coastguard Worker }
5446*4f2df630SAndroid Build Coastguard Worker transferred_sections = transfer_image(&td, match);
5447*4f2df630SAndroid Build Coastguard Worker }
5448*4f2df630SAndroid Build Coastguard Worker
5449*4f2df630SAndroid Build Coastguard Worker /* Free images */
5450*4f2df630SAndroid Build Coastguard Worker match = NULL;
5451*4f2df630SAndroid Build Coastguard Worker for (i = 0; i < num_images; i++)
5452*4f2df630SAndroid Build Coastguard Worker free(images[i].data);
5453*4f2df630SAndroid Build Coastguard Worker free(images);
5454*4f2df630SAndroid Build Coastguard Worker images = NULL;
5455*4f2df630SAndroid Build Coastguard Worker
5456*4f2df630SAndroid Build Coastguard Worker /*
5457*4f2df630SAndroid Build Coastguard Worker * Move USB updater sate machine to idle state so that
5458*4f2df630SAndroid Build Coastguard Worker * vendor commands can be processed later, if any.
5459*4f2df630SAndroid Build Coastguard Worker */
5460*4f2df630SAndroid Build Coastguard Worker if (td.ep_type == usb_xfer)
5461*4f2df630SAndroid Build Coastguard Worker send_done(&td.uep);
5462*4f2df630SAndroid Build Coastguard Worker
5463*4f2df630SAndroid Build Coastguard Worker if (transferred_sections)
5464*4f2df630SAndroid Build Coastguard Worker generate_reset_request(&td);
5465*4f2df630SAndroid Build Coastguard Worker
5466*4f2df630SAndroid Build Coastguard Worker if (show_fw_ver) {
5467*4f2df630SAndroid Build Coastguard Worker if (show_machine_output) {
5468*4f2df630SAndroid Build Coastguard Worker print_machine_output("RO_FW_VER", "%d.%d.%d",
5469*4f2df630SAndroid Build Coastguard Worker targ.shv[0].epoch,
5470*4f2df630SAndroid Build Coastguard Worker targ.shv[0].major,
5471*4f2df630SAndroid Build Coastguard Worker targ.shv[0].minor);
5472*4f2df630SAndroid Build Coastguard Worker print_machine_output("RW_FW_VER", "%d.%d.%d",
5473*4f2df630SAndroid Build Coastguard Worker targ.shv[1].epoch,
5474*4f2df630SAndroid Build Coastguard Worker targ.shv[1].major,
5475*4f2df630SAndroid Build Coastguard Worker targ.shv[1].minor);
5476*4f2df630SAndroid Build Coastguard Worker } else {
5477*4f2df630SAndroid Build Coastguard Worker printf("Current versions:\n");
5478*4f2df630SAndroid Build Coastguard Worker printf("RO %d.%d.%d\n", targ.shv[0].epoch,
5479*4f2df630SAndroid Build Coastguard Worker targ.shv[0].major, targ.shv[0].minor);
5480*4f2df630SAndroid Build Coastguard Worker printf("RW %d.%d.%d\n", targ.shv[1].epoch,
5481*4f2df630SAndroid Build Coastguard Worker targ.shv[1].major, targ.shv[1].minor);
5482*4f2df630SAndroid Build Coastguard Worker }
5483*4f2df630SAndroid Build Coastguard Worker }
5484*4f2df630SAndroid Build Coastguard Worker }
5485*4f2df630SAndroid Build Coastguard Worker
5486*4f2df630SAndroid Build Coastguard Worker if (td.ep_type == usb_xfer) {
5487*4f2df630SAndroid Build Coastguard Worker libusb_close(td.uep.devh);
5488*4f2df630SAndroid Build Coastguard Worker libusb_exit(NULL);
5489*4f2df630SAndroid Build Coastguard Worker }
5490*4f2df630SAndroid Build Coastguard Worker
5491*4f2df630SAndroid Build Coastguard Worker if (!transferred_sections)
5492*4f2df630SAndroid Build Coastguard Worker return noop;
5493*4f2df630SAndroid Build Coastguard Worker
5494*4f2df630SAndroid Build Coastguard Worker printf("image updated\n");
5495*4f2df630SAndroid Build Coastguard Worker return all_updated;
5496*4f2df630SAndroid Build Coastguard Worker }
5497