blob: e6798e04799ecd946f85f3b81115e365013b7ff7 [file] [log] [blame]
Yann Gautiereb16b472018-10-15 09:36:32 +02001/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <boot_api.h>
9#include <debug.h>
10#include <errno.h>
11#include <io_driver.h>
12#include <io_stm32image.h>
13#include <io_storage.h>
14#include <platform.h>
15#include <platform_def.h>
16#include <stdint.h>
17#include <string.h>
18#include <utils.h>
19
20static uintptr_t backend_dev_handle;
21static uintptr_t backend_image_spec;
22static uint32_t *stm32_img;
23static uint8_t first_lba_buffer[MAX_LBA_SIZE] __aligned(4);
24static struct stm32image_part_info *current_part;
25
26/* STM32 Image driver functions */
27static int stm32image_dev_open(const uintptr_t init_params,
28 io_dev_info_t **dev_info);
29static int stm32image_partition_open(io_dev_info_t *dev_info,
30 const uintptr_t spec, io_entity_t *entity);
31static int stm32image_partition_size(io_entity_t *entity, size_t *length);
32static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
33 size_t length, size_t *length_read);
34static int stm32image_partition_close(io_entity_t *entity);
35static int stm32image_dev_init(io_dev_info_t *dev_info,
36 const uintptr_t init_params);
37static int stm32image_dev_close(io_dev_info_t *dev_info);
38
39/* Identify the device type as a virtual driver */
40static io_type_t device_type_stm32image(void)
41{
42 return IO_TYPE_STM32IMAGE;
43}
44
45static const io_dev_connector_t stm32image_dev_connector = {
46 .dev_open = stm32image_dev_open
47};
48
49static const io_dev_funcs_t stm32image_dev_funcs = {
50 .type = device_type_stm32image,
51 .open = stm32image_partition_open,
52 .size = stm32image_partition_size,
53 .read = stm32image_partition_read,
54 .close = stm32image_partition_close,
55 .dev_init = stm32image_dev_init,
56 .dev_close = stm32image_dev_close,
57};
58
59static io_dev_info_t stm32image_dev_info = {
60 .funcs = &stm32image_dev_funcs,
61 .info = (uintptr_t)0,
62};
63
64static struct stm32image_device_info stm32image_dev;
65
66static int get_part_idx_by_binary_type(uint32_t binary_type)
67{
68 int i;
69
70 for (i = 0; i < STM32_PART_NUM; i++) {
71 if (stm32image_dev.part_info[i].binary_type == binary_type) {
72 return i;
73 }
74 }
75
76 return -EINVAL;
77}
78
79/* Open a connection to the STM32IMAGE device */
80static int stm32image_dev_open(const uintptr_t init_params,
81 io_dev_info_t **dev_info)
82{
83 int i;
84 struct stm32image_device_info *device_info =
85 (struct stm32image_device_info *)init_params;
86
87 assert(dev_info != NULL);
88 *dev_info = (io_dev_info_t *)&stm32image_dev_info;
89
90 stm32image_dev.device_size = device_info->device_size;
91 stm32image_dev.lba_size = device_info->lba_size;
92
93 for (i = 0; i < STM32_PART_NUM; i++) {
94 memcpy(stm32image_dev.part_info[i].name,
95 device_info->part_info[i].name, MAX_PART_NAME_SIZE);
96 stm32image_dev.part_info[i].part_offset =
97 device_info->part_info[i].part_offset;
98 stm32image_dev.part_info[i].bkp_offset =
99 device_info->part_info[i].bkp_offset;
100 }
101
102 return 0;
103}
104
105/* Do some basic package checks */
106static int stm32image_dev_init(io_dev_info_t *dev_info,
107 const uintptr_t init_params)
108{
109 int result;
110
111 if ((backend_dev_handle != 0U) || (backend_image_spec != 0U)) {
112 ERROR("STM32 Image io supports only one session\n");
113 return -ENOMEM;
114 }
115
116 /* Obtain a reference to the image by querying the platform layer */
117 result = plat_get_image_source(STM32_IMAGE_ID, &backend_dev_handle,
118 &backend_image_spec);
119 if (result != 0) {
120 ERROR("STM32 image error (%i)\n", result);
121 return -EINVAL;
122 }
123
124 return result;
125}
126
127/* Close a connection to the STM32 Image device */
128static int stm32image_dev_close(io_dev_info_t *dev_info)
129{
130 backend_dev_handle = 0U;
131 backend_image_spec = 0U;
132 stm32_img = NULL;
133
134 return 0;
135}
136
137/* Open a partition */
138static int stm32image_partition_open(io_dev_info_t *dev_info,
139 const uintptr_t spec, io_entity_t *entity)
140{
141 const struct stm32image_part_info *partition_spec;
142 int idx;
143
144 assert(entity != NULL);
145
146 partition_spec = (struct stm32image_part_info *)spec;
147 assert(partition_spec != NULL);
148
149 idx = get_part_idx_by_binary_type(partition_spec->binary_type);
150 if ((idx < 0) || (idx > STM32_PART_NUM)) {
151 ERROR("Wrong partition index (%d)\n", idx);
152 return -EINVAL;
153 }
154
155 current_part = &stm32image_dev.part_info[idx];
156 stm32_img = (uint32_t *)&current_part->part_offset;
157
158 return 0;
159}
160
161/* Return the size of a partition */
162static int stm32image_partition_size(io_entity_t *entity, size_t *length)
163{
164 int result;
165 uintptr_t backend_handle;
166 size_t bytes_read;
167 boot_api_image_header_t *header =
168 (boot_api_image_header_t *)first_lba_buffer;
169
170 assert(entity != NULL);
171 assert(length != NULL);
172
173 /* Attempt to access the image */
174 result = io_open(backend_dev_handle, backend_image_spec,
175 &backend_handle);
176
177 if (result < 0) {
178 ERROR("%s: io_open (%i)\n", __func__, result);
179 return result;
180 }
181
182 /* Reset magic header value */
183 header->magic = 0;
184
185 while (header->magic == 0U) {
186 result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img);
187 if (result != 0) {
188 ERROR("%s: io_seek (%i)\n", __func__, result);
189 break;
190 }
191
192 result = io_read(backend_handle, (uintptr_t)header,
193 MAX_LBA_SIZE, (size_t *)&bytes_read);
194 if (result != 0) {
195 ERROR("%s: io_read (%i)\n", __func__, result);
196 break;
197 }
198
199 if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
200 (header->binary_type != current_part->binary_type) ||
201 (header->image_length >= stm32image_dev.device_size)) {
202 WARN("%s: partition %s wrong header\n",
203 __func__, current_part->name);
204
205 /* Header not correct, check next offset for backup */
206 *stm32_img += current_part->bkp_offset;
207 if (*stm32_img > stm32image_dev.device_size) {
208 /* No backup found, end of device reached */
209 WARN("Out of memory\n");
210 result = -ENOMEM;
211 break;
212 }
213 header->magic = 0;
214 }
215 }
216
217 io_close(backend_handle);
218
219 if (result != 0) {
220 return result;
221 }
222
223 *length = header->image_length;
224
225 INFO("STM32 Image size : %i\n", *length);
226
227 return 0;
228}
229
230static int check_header(boot_api_image_header_t *header, uintptr_t buffer)
231{
232 uint32_t i;
233 uint32_t img_checksum = 0;
234
235 /*
236 * Check header/payload validity:
237 * - Header magic
238 * - Header version
239 * - Payload checksum
240 */
241 if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
242 ERROR("Header magic\n");
243 return -EINVAL;
244 }
245
246 if (header->header_version != BOOT_API_HEADER_VERSION) {
247 ERROR("Header version\n");
248 return -EINVAL;
249 }
250
251 for (i = 0; i < header->image_length; i++) {
252 img_checksum += *(uint8_t *)(buffer + i);
253 }
254
255 if (header->payload_checksum != img_checksum) {
256 ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum,
257 header->payload_checksum);
258 return -EINVAL;
259 }
260
261 return 0;
262}
263
264/* Read data from a partition */
265static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
266 size_t length, size_t *length_read)
267{
268 int result = 0, offset, local_length = 0;
269 uint8_t *local_buffer = (uint8_t *)buffer;
270 boot_api_image_header_t *header =
271 (boot_api_image_header_t *)first_lba_buffer;
272 uintptr_t backend_handle;
273
274 assert(entity != NULL);
275 assert(buffer != 0U);
276 assert(length_read != NULL);
277
278 *length_read = 0U;
279
280 while (*length_read == 0U) {
281 if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
282 /* Check for backup as image is corrupted */
283 *stm32_img += current_part->bkp_offset;
284 if (*stm32_img >= stm32image_dev.device_size) {
285 /* End of device reached */
286 result = -ENOMEM;
287 break;
288 }
289
290 local_buffer = (uint8_t *)buffer;
291
292 result = stm32image_partition_size(entity, &length);
293 if (result != 0) {
294 break;
295 }
296 }
297
298 /* Part of image already loaded with the header */
299 memcpy(local_buffer, (uint8_t *)first_lba_buffer +
300 sizeof(boot_api_image_header_t),
301 MAX_LBA_SIZE - sizeof(boot_api_image_header_t));
302 local_buffer += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
303 offset = MAX_LBA_SIZE;
304
305 /* New image length to be read */
306 local_length = round_up(length -
307 ((MAX_LBA_SIZE) -
308 sizeof(boot_api_image_header_t)),
309 stm32image_dev.lba_size);
310
311 if ((header->load_address != 0U) &&
312 (header->load_address != buffer)) {
313 ERROR("Wrong load address\n");
314 panic();
315 }
316
317 result = io_open(backend_dev_handle, backend_image_spec,
318 &backend_handle);
319
320 if (result != 0) {
321 ERROR("%s: io_open (%i)\n", __func__, result);
322 break;
323 }
324
325 result = io_seek(backend_handle, IO_SEEK_SET,
326 *stm32_img + offset);
327
328 if (result != 0) {
329 ERROR("%s: io_seek (%i)\n", __func__, result);
330 *length_read = 0;
331 io_close(backend_handle);
332 break;
333 }
334
335 result = io_read(backend_handle, (uintptr_t)local_buffer,
336 local_length, length_read);
337
338 /* Adding part of size already read from header */
339 *length_read += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
340
341 if (result != 0) {
342 ERROR("%s: io_read (%i)\n", __func__, result);
343 *length_read = 0;
344 io_close(backend_handle);
345 break;
346 }
347
348 result = check_header(header, buffer);
349 if (result != 0) {
350 ERROR("Header check failed\n");
351 *length_read = 0;
352 header->magic = 0;
353 io_close(backend_handle);
354 break;
355 }
356
357 io_close(backend_handle);
358 }
359
360 return result;
361}
362
363/* Close a partition */
364static int stm32image_partition_close(io_entity_t *entity)
365{
366 current_part = NULL;
367
368 return 0;
369}
370
371/* Register the stm32image driver with the IO abstraction */
372int register_io_dev_stm32image(const io_dev_connector_t **dev_con)
373{
374 int result;
375
376 assert(dev_con != NULL);
377
378 result = io_register_device(&stm32image_dev_info);
379 if (result == 0) {
380 *dev_con = &stm32image_dev_connector;
381 }
382
383 return result;
384}