aboutsummaryrefslogtreecommitdiff
path: root/drivers/fwu/fwu.c
blob: 7cb4c2982c697710899bda66076a9e1c80d6457e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
 * Copyright (c) 2021, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>

#include <common/debug.h>
#include <common/tf_crc32.h>
#include <common/tbbr/tbbr_img_def.h>
#include <drivers/fwu/fwu.h>
#include <drivers/fwu/fwu_metadata.h>
#include <drivers/io/io_storage.h>

#include <plat/common/platform.h>

/*
 * Assert that crc_32 is the first member of fwu_metadata structure.
 * It avoids accessing data outside of the metadata structure during
 * CRC32 computation if the crc_32 field gets moved due the structure
 * member(s) addition in the future.
 */
CASSERT((offsetof(struct fwu_metadata, crc_32) == 0),
	crc_32_must_be_first_member_of_structure);

static struct fwu_metadata metadata;
static bool is_fwu_initialized;

/*******************************************************************************
 * Compute CRC32 of the FWU metadata, and check it against the CRC32 value
 * present in the FWU metadata.
 *
 * return -1 on error, otherwise 0
 ******************************************************************************/
static int fwu_metadata_crc_check(void)
{
	unsigned char *data = (unsigned char *)&metadata;

	uint32_t calc_crc = tf_crc32(0U, data + sizeof(metadata.crc_32),
				     (sizeof(metadata) -
				      sizeof(metadata.crc_32)));

	if (metadata.crc_32 != calc_crc) {
		return -1;
	}

	return 0;
}

/*******************************************************************************
 * Check the sanity of FWU metadata.
 *
 * return -1 on error, otherwise 0
 ******************************************************************************/
static int fwu_metadata_sanity_check(void)
{
	/* ToDo: add more conditions for sanity check */
	if ((metadata.active_index >= NR_OF_FW_BANKS) ||
	    (metadata.previous_active_index >= NR_OF_FW_BANKS)) {
		return -1;
	}

	return 0;
}

/*******************************************************************************
 * Verify and load specified FWU metadata image to local FWU metadata structure.
 *
 * @image_id: FWU metadata image id (either FWU_METADATA_IMAGE_ID or
 *				     BKUP_FWU_METADATA_IMAGE_ID)
 *
 * return a negative value on error, otherwise 0
 ******************************************************************************/
static int fwu_metadata_load(unsigned int image_id)
{
	int result;
	uintptr_t dev_handle, image_handle, image_spec;
	size_t bytes_read;

	assert((image_id == FWU_METADATA_IMAGE_ID) ||
	       (image_id == BKUP_FWU_METADATA_IMAGE_ID));

	result = plat_fwu_set_metadata_image_source(image_id,
						    &dev_handle,
						    &image_spec);
	if (result != 0) {
		WARN("Failed to set reference to image id=%u (%i)\n",
		     image_id, result);
		return result;
	}

	result = io_open(dev_handle, image_spec, &image_handle);
	if (result != 0) {
		WARN("Failed to load image id id=%u (%i)\n",
		     image_id, result);
		return result;
	}

	result = io_read(image_handle, (uintptr_t)&metadata,
			 sizeof(struct fwu_metadata), &bytes_read);

	if (result != 0) {
		WARN("Failed to read image id=%u (%i)\n", image_id, result);
		goto exit;
	}

	if (sizeof(struct fwu_metadata) != bytes_read) {
		/* return -1 in case of partial/no read */
		result = -1;
		WARN("Read bytes (%zu) instead of expected (%zu) bytes\n",
		     bytes_read, sizeof(struct fwu_metadata));
		goto exit;
	}

	/* sanity check on loaded parameters */
	result = fwu_metadata_sanity_check();
	if (result != 0) {
		WARN("Sanity %s\n", "check failed on FWU metadata");
		goto exit;
	}

	/* CRC check on loaded parameters */
	result = fwu_metadata_crc_check();
	if (result != 0) {
		WARN("CRC %s\n", "check failed on FWU metadata");
	}

exit:
	(void)io_close(image_handle);

	return result;
}

/*******************************************************************************
 * The system runs in the trial run state if any of the images in the active
 * firmware bank has not been accepted yet.
 *
 * Returns true if the system is running in the trial state.
 ******************************************************************************/
bool fwu_is_trial_run_state(void)
{
	bool trial_run = false;

	assert(is_fwu_initialized == true);

	for (unsigned int i = 0U; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
		struct fwu_image_entry *entry = &metadata.img_entry[i];
		struct fwu_image_properties *img_props =
			&entry->img_props[metadata.active_index];
		if (img_props->accepted == 0) {
			trial_run = true;
			break;
		}
	}

	return trial_run;
}

/*******************************************************************************
 * Load verified copy of FWU metadata image kept in the platform NV storage
 * into local FWU metadata structure.
 * Also, update platform I/O policies with the offset address and length of
 * firmware-updated images kept in the platform NV storage.
 ******************************************************************************/
void fwu_init(void)
{
	/* Load FWU metadata which will be used to load the images in the
	 * active bank as per PSA FWU specification
	 */
	int result = fwu_metadata_load(FWU_METADATA_IMAGE_ID);

	if (result != 0) {
		WARN("loading of FWU-Metadata failed, "
		     "using Bkup-FWU-Metadata\n");

		result = fwu_metadata_load(BKUP_FWU_METADATA_IMAGE_ID);
		if (result != 0) {
			ERROR("loading of Bkup-FWU-Metadata failed\n");
			panic();
		}
	}

	plat_fwu_set_images_source(&metadata);

	is_fwu_initialized = true;
}