xref: /arm-trusted-firmware/drivers/io/io_fip.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <stdint.h>
10*91f16700Schasinglulu #include <string.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <platform_def.h>
13*91f16700Schasinglulu 
14*91f16700Schasinglulu #include <common/bl_common.h>
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <drivers/io/io_driver.h>
17*91f16700Schasinglulu #include <drivers/io/io_fip.h>
18*91f16700Schasinglulu #include <drivers/io/io_storage.h>
19*91f16700Schasinglulu #include <lib/utils.h>
20*91f16700Schasinglulu #include <plat/common/platform.h>
21*91f16700Schasinglulu #include <tools_share/firmware_image_package.h>
22*91f16700Schasinglulu #include <tools_share/uuid.h>
23*91f16700Schasinglulu 
24*91f16700Schasinglulu #ifndef MAX_FIP_DEVICES
25*91f16700Schasinglulu #define MAX_FIP_DEVICES		1
26*91f16700Schasinglulu #endif
27*91f16700Schasinglulu 
28*91f16700Schasinglulu /* Useful for printing UUIDs when debugging.*/
29*91f16700Schasinglulu #define PRINT_UUID2(x)								\
30*91f16700Schasinglulu 	"%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",	\
31*91f16700Schasinglulu 		x.time_low, x.time_mid, x.time_hi_and_version,			\
32*91f16700Schasinglulu 		x.clock_seq_hi_and_reserved, x.clock_seq_low,			\
33*91f16700Schasinglulu 		x.node[0], x.node[1], x.node[2], x.node[3],			\
34*91f16700Schasinglulu 		x.node[4], x.node[5]
35*91f16700Schasinglulu 
36*91f16700Schasinglulu typedef struct {
37*91f16700Schasinglulu 	unsigned int file_pos;
38*91f16700Schasinglulu 	fip_toc_entry_t entry;
39*91f16700Schasinglulu } fip_file_state_t;
40*91f16700Schasinglulu 
41*91f16700Schasinglulu /*
42*91f16700Schasinglulu  * Maintain dev_spec per FIP Device
43*91f16700Schasinglulu  * TODO - Add backend handles and file state
44*91f16700Schasinglulu  * per FIP device here once backends like io_memmap
45*91f16700Schasinglulu  * can support multiple open files
46*91f16700Schasinglulu  */
47*91f16700Schasinglulu typedef struct {
48*91f16700Schasinglulu 	uintptr_t dev_spec;
49*91f16700Schasinglulu 	uint16_t plat_toc_flag;
50*91f16700Schasinglulu } fip_dev_state_t;
51*91f16700Schasinglulu 
52*91f16700Schasinglulu /*
53*91f16700Schasinglulu  * Only one file can be open across all FIP device
54*91f16700Schasinglulu  * as backends like io_memmap don't support
55*91f16700Schasinglulu  * multiple open files. The file state and
56*91f16700Schasinglulu  * backend handle should be maintained per FIP device
57*91f16700Schasinglulu  * if the same support is available in the backend
58*91f16700Schasinglulu  */
59*91f16700Schasinglulu static fip_file_state_t current_fip_file = {0};
60*91f16700Schasinglulu static uintptr_t backend_dev_handle;
61*91f16700Schasinglulu static uintptr_t backend_image_spec;
62*91f16700Schasinglulu 
63*91f16700Schasinglulu static fip_dev_state_t state_pool[MAX_FIP_DEVICES];
64*91f16700Schasinglulu static io_dev_info_t dev_info_pool[MAX_FIP_DEVICES];
65*91f16700Schasinglulu 
66*91f16700Schasinglulu /* Track number of allocated fip devices */
67*91f16700Schasinglulu static unsigned int fip_dev_count;
68*91f16700Schasinglulu 
69*91f16700Schasinglulu /* Firmware Image Package driver functions */
70*91f16700Schasinglulu static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
71*91f16700Schasinglulu static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
72*91f16700Schasinglulu 			  io_entity_t *entity);
73*91f16700Schasinglulu static int fip_file_len(io_entity_t *entity, size_t *length);
74*91f16700Schasinglulu static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
75*91f16700Schasinglulu 			  size_t *length_read);
76*91f16700Schasinglulu static int fip_file_close(io_entity_t *entity);
77*91f16700Schasinglulu static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
78*91f16700Schasinglulu static int fip_dev_close(io_dev_info_t *dev_info);
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 
81*91f16700Schasinglulu /* Return 0 for equal uuids. */
82*91f16700Schasinglulu static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
83*91f16700Schasinglulu {
84*91f16700Schasinglulu 	return memcmp(uuid1, uuid2, sizeof(uuid_t));
85*91f16700Schasinglulu }
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 
88*91f16700Schasinglulu static inline int is_valid_header(fip_toc_header_t *header)
89*91f16700Schasinglulu {
90*91f16700Schasinglulu 	if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) {
91*91f16700Schasinglulu 		return 1;
92*91f16700Schasinglulu 	} else {
93*91f16700Schasinglulu 		return 0;
94*91f16700Schasinglulu 	}
95*91f16700Schasinglulu }
96*91f16700Schasinglulu 
97*91f16700Schasinglulu 
98*91f16700Schasinglulu /* Identify the device type as a virtual driver */
99*91f16700Schasinglulu static io_type_t device_type_fip(void)
100*91f16700Schasinglulu {
101*91f16700Schasinglulu 	return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
102*91f16700Schasinglulu }
103*91f16700Schasinglulu 
104*91f16700Schasinglulu 
105*91f16700Schasinglulu static const io_dev_connector_t fip_dev_connector = {
106*91f16700Schasinglulu 	.dev_open = fip_dev_open
107*91f16700Schasinglulu };
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 
110*91f16700Schasinglulu static const io_dev_funcs_t fip_dev_funcs = {
111*91f16700Schasinglulu 	.type = device_type_fip,
112*91f16700Schasinglulu 	.open = fip_file_open,
113*91f16700Schasinglulu 	.seek = NULL,
114*91f16700Schasinglulu 	.size = fip_file_len,
115*91f16700Schasinglulu 	.read = fip_file_read,
116*91f16700Schasinglulu 	.write = NULL,
117*91f16700Schasinglulu 	.close = fip_file_close,
118*91f16700Schasinglulu 	.dev_init = fip_dev_init,
119*91f16700Schasinglulu 	.dev_close = fip_dev_close,
120*91f16700Schasinglulu };
121*91f16700Schasinglulu 
122*91f16700Schasinglulu /* Locate a file state in the pool, specified by address */
123*91f16700Schasinglulu static int find_first_fip_state(const uintptr_t dev_spec,
124*91f16700Schasinglulu 				  unsigned int *index_out)
125*91f16700Schasinglulu {
126*91f16700Schasinglulu 	int result = -ENOENT;
127*91f16700Schasinglulu 	unsigned int index;
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 	for (index = 0; index < (unsigned int)MAX_FIP_DEVICES; ++index) {
130*91f16700Schasinglulu 		/* dev_spec is used as identifier since it's unique */
131*91f16700Schasinglulu 		if (state_pool[index].dev_spec == dev_spec) {
132*91f16700Schasinglulu 			result = 0;
133*91f16700Schasinglulu 			*index_out = index;
134*91f16700Schasinglulu 			break;
135*91f16700Schasinglulu 		}
136*91f16700Schasinglulu 	}
137*91f16700Schasinglulu 	return result;
138*91f16700Schasinglulu }
139*91f16700Schasinglulu 
140*91f16700Schasinglulu 
141*91f16700Schasinglulu /* Allocate a device info from the pool and return a pointer to it */
142*91f16700Schasinglulu static int allocate_dev_info(io_dev_info_t **dev_info)
143*91f16700Schasinglulu {
144*91f16700Schasinglulu 	int result = -ENOMEM;
145*91f16700Schasinglulu 
146*91f16700Schasinglulu 	assert(dev_info != NULL);
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	if (fip_dev_count < (unsigned int)MAX_FIP_DEVICES) {
149*91f16700Schasinglulu 		unsigned int index = 0;
150*91f16700Schasinglulu 
151*91f16700Schasinglulu 		result = find_first_fip_state(0, &index);
152*91f16700Schasinglulu 		assert(result == 0);
153*91f16700Schasinglulu 		/* initialize dev_info */
154*91f16700Schasinglulu 		dev_info_pool[index].funcs = &fip_dev_funcs;
155*91f16700Schasinglulu 		dev_info_pool[index].info =
156*91f16700Schasinglulu 				(uintptr_t)&state_pool[index];
157*91f16700Schasinglulu 		*dev_info = &dev_info_pool[index];
158*91f16700Schasinglulu 		++fip_dev_count;
159*91f16700Schasinglulu 	}
160*91f16700Schasinglulu 
161*91f16700Schasinglulu 	return result;
162*91f16700Schasinglulu }
163*91f16700Schasinglulu 
164*91f16700Schasinglulu /* Release a device info to the pool */
165*91f16700Schasinglulu static int free_dev_info(io_dev_info_t *dev_info)
166*91f16700Schasinglulu {
167*91f16700Schasinglulu 	int result;
168*91f16700Schasinglulu 	unsigned int index = 0;
169*91f16700Schasinglulu 	fip_dev_state_t *state;
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	assert(dev_info != NULL);
172*91f16700Schasinglulu 
173*91f16700Schasinglulu 	state = (fip_dev_state_t *)dev_info->info;
174*91f16700Schasinglulu 	result = find_first_fip_state(state->dev_spec, &index);
175*91f16700Schasinglulu 	if (result ==  0) {
176*91f16700Schasinglulu 		/* free if device info is valid */
177*91f16700Schasinglulu 		zeromem(state, sizeof(fip_dev_state_t));
178*91f16700Schasinglulu 		--fip_dev_count;
179*91f16700Schasinglulu 	}
180*91f16700Schasinglulu 
181*91f16700Schasinglulu 	return result;
182*91f16700Schasinglulu }
183*91f16700Schasinglulu 
184*91f16700Schasinglulu /*
185*91f16700Schasinglulu  * Multiple FIP devices can be opened depending on the value of
186*91f16700Schasinglulu  * MAX_FIP_DEVICES. Given that there is only one backend, only a
187*91f16700Schasinglulu  * single file can be open at a time by any FIP device.
188*91f16700Schasinglulu  */
189*91f16700Schasinglulu static int fip_dev_open(const uintptr_t dev_spec,
190*91f16700Schasinglulu 			 io_dev_info_t **dev_info)
191*91f16700Schasinglulu {
192*91f16700Schasinglulu 	int result;
193*91f16700Schasinglulu 	io_dev_info_t *info;
194*91f16700Schasinglulu 	fip_dev_state_t *state;
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	assert(dev_info != NULL);
197*91f16700Schasinglulu #if MAX_FIP_DEVICES > 1
198*91f16700Schasinglulu 	assert(dev_spec != (uintptr_t)NULL);
199*91f16700Schasinglulu #endif
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	result = allocate_dev_info(&info);
202*91f16700Schasinglulu 	if (result != 0)
203*91f16700Schasinglulu 		return -ENOMEM;
204*91f16700Schasinglulu 
205*91f16700Schasinglulu 	state = (fip_dev_state_t *)info->info;
206*91f16700Schasinglulu 
207*91f16700Schasinglulu 	state->dev_spec = dev_spec;
208*91f16700Schasinglulu 
209*91f16700Schasinglulu 	*dev_info = info;
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 	return 0;
212*91f16700Schasinglulu }
213*91f16700Schasinglulu 
214*91f16700Schasinglulu 
215*91f16700Schasinglulu /* Do some basic package checks. */
216*91f16700Schasinglulu static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
217*91f16700Schasinglulu {
218*91f16700Schasinglulu 	int result;
219*91f16700Schasinglulu 	unsigned int image_id = (unsigned int)init_params;
220*91f16700Schasinglulu 	uintptr_t backend_handle;
221*91f16700Schasinglulu 	fip_toc_header_t header;
222*91f16700Schasinglulu 	size_t bytes_read;
223*91f16700Schasinglulu 	fip_dev_state_t *state;
224*91f16700Schasinglulu 
225*91f16700Schasinglulu 	assert(dev_info != NULL);
226*91f16700Schasinglulu 
227*91f16700Schasinglulu 	state = (fip_dev_state_t *)dev_info->info;
228*91f16700Schasinglulu 
229*91f16700Schasinglulu 	/* Obtain a reference to the image by querying the platform layer */
230*91f16700Schasinglulu 	result = plat_get_image_source(image_id, &backend_dev_handle,
231*91f16700Schasinglulu 				       &backend_image_spec);
232*91f16700Schasinglulu 	if (result != 0) {
233*91f16700Schasinglulu 		WARN("Failed to obtain reference to image id=%u (%i)\n",
234*91f16700Schasinglulu 			image_id, result);
235*91f16700Schasinglulu 		result = -ENOENT;
236*91f16700Schasinglulu 		goto fip_dev_init_exit;
237*91f16700Schasinglulu 	}
238*91f16700Schasinglulu 
239*91f16700Schasinglulu 	/* Attempt to access the FIP image */
240*91f16700Schasinglulu 	result = io_open(backend_dev_handle, backend_image_spec,
241*91f16700Schasinglulu 			 &backend_handle);
242*91f16700Schasinglulu 	if (result != 0) {
243*91f16700Schasinglulu 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
244*91f16700Schasinglulu 		result = -ENOENT;
245*91f16700Schasinglulu 		goto fip_dev_init_exit;
246*91f16700Schasinglulu 	}
247*91f16700Schasinglulu 
248*91f16700Schasinglulu 	result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
249*91f16700Schasinglulu 			&bytes_read);
250*91f16700Schasinglulu 	if (result == 0) {
251*91f16700Schasinglulu 		if (!is_valid_header(&header)) {
252*91f16700Schasinglulu 			WARN("Firmware Image Package header check failed.\n");
253*91f16700Schasinglulu 			result = -ENOENT;
254*91f16700Schasinglulu 		} else {
255*91f16700Schasinglulu 			VERBOSE("FIP header looks OK.\n");
256*91f16700Schasinglulu 			/*
257*91f16700Schasinglulu 			 * Store 16-bit Platform ToC flags field which occupies
258*91f16700Schasinglulu 			 * bits [32-47] in fip header.
259*91f16700Schasinglulu 			 */
260*91f16700Schasinglulu 			state->plat_toc_flag = (header.flags >> 32) & 0xffff;
261*91f16700Schasinglulu 		}
262*91f16700Schasinglulu 	}
263*91f16700Schasinglulu 
264*91f16700Schasinglulu 	io_close(backend_handle);
265*91f16700Schasinglulu 
266*91f16700Schasinglulu  fip_dev_init_exit:
267*91f16700Schasinglulu 	return result;
268*91f16700Schasinglulu }
269*91f16700Schasinglulu 
270*91f16700Schasinglulu /* Close a connection to the FIP device */
271*91f16700Schasinglulu static int fip_dev_close(io_dev_info_t *dev_info)
272*91f16700Schasinglulu {
273*91f16700Schasinglulu 	/* TODO: Consider tracking open files and cleaning them up here */
274*91f16700Schasinglulu 
275*91f16700Schasinglulu 	/* Clear the backend. */
276*91f16700Schasinglulu 	backend_dev_handle = (uintptr_t)NULL;
277*91f16700Schasinglulu 	backend_image_spec = (uintptr_t)NULL;
278*91f16700Schasinglulu 
279*91f16700Schasinglulu 	return free_dev_info(dev_info);
280*91f16700Schasinglulu }
281*91f16700Schasinglulu 
282*91f16700Schasinglulu 
283*91f16700Schasinglulu /* Open a file for access from package. */
284*91f16700Schasinglulu static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
285*91f16700Schasinglulu 			 io_entity_t *entity)
286*91f16700Schasinglulu {
287*91f16700Schasinglulu 	int result;
288*91f16700Schasinglulu 	uintptr_t backend_handle;
289*91f16700Schasinglulu 	const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
290*91f16700Schasinglulu 	static const uuid_t uuid_null = { {0} }; /* Double braces for clang */
291*91f16700Schasinglulu 	size_t bytes_read;
292*91f16700Schasinglulu 	int found_file = 0;
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 	assert(uuid_spec != NULL);
295*91f16700Schasinglulu 	assert(entity != NULL);
296*91f16700Schasinglulu 
297*91f16700Schasinglulu 	/* Can only have one file open at a time for the moment. We need to
298*91f16700Schasinglulu 	 * track state like file cursor position. We know the header lives at
299*91f16700Schasinglulu 	 * offset zero, so this entry should never be zero for an active file.
300*91f16700Schasinglulu 	 * When the system supports dynamic memory allocation we can allow more
301*91f16700Schasinglulu 	 * than one open file at a time if needed.
302*91f16700Schasinglulu 	 */
303*91f16700Schasinglulu 	if (current_fip_file.entry.offset_address != 0U) {
304*91f16700Schasinglulu 		WARN("fip_file_open : Only one open file at a time.\n");
305*91f16700Schasinglulu 		return -ENFILE;
306*91f16700Schasinglulu 	}
307*91f16700Schasinglulu 
308*91f16700Schasinglulu 	/* Attempt to access the FIP image */
309*91f16700Schasinglulu 	result = io_open(backend_dev_handle, backend_image_spec,
310*91f16700Schasinglulu 			 &backend_handle);
311*91f16700Schasinglulu 	if (result != 0) {
312*91f16700Schasinglulu 		WARN("Failed to open Firmware Image Package (%i)\n", result);
313*91f16700Schasinglulu 		result = -ENOENT;
314*91f16700Schasinglulu 		goto fip_file_open_exit;
315*91f16700Schasinglulu 	}
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	/* Seek past the FIP header into the Table of Contents */
318*91f16700Schasinglulu 	result = io_seek(backend_handle, IO_SEEK_SET,
319*91f16700Schasinglulu 			 (signed long long)sizeof(fip_toc_header_t));
320*91f16700Schasinglulu 	if (result != 0) {
321*91f16700Schasinglulu 		WARN("fip_file_open: failed to seek\n");
322*91f16700Schasinglulu 		result = -ENOENT;
323*91f16700Schasinglulu 		goto fip_file_open_close;
324*91f16700Schasinglulu 	}
325*91f16700Schasinglulu 
326*91f16700Schasinglulu 	found_file = 0;
327*91f16700Schasinglulu 	do {
328*91f16700Schasinglulu 		result = io_read(backend_handle,
329*91f16700Schasinglulu 				 (uintptr_t)&current_fip_file.entry,
330*91f16700Schasinglulu 				 sizeof(current_fip_file.entry),
331*91f16700Schasinglulu 				 &bytes_read);
332*91f16700Schasinglulu 		if (result == 0) {
333*91f16700Schasinglulu 			if (compare_uuids(&current_fip_file.entry.uuid,
334*91f16700Schasinglulu 					  &uuid_spec->uuid) == 0) {
335*91f16700Schasinglulu 				found_file = 1;
336*91f16700Schasinglulu 			}
337*91f16700Schasinglulu 		} else {
338*91f16700Schasinglulu 			WARN("Failed to read FIP (%i)\n", result);
339*91f16700Schasinglulu 			goto fip_file_open_close;
340*91f16700Schasinglulu 		}
341*91f16700Schasinglulu 	} while ((found_file == 0) &&
342*91f16700Schasinglulu 			(compare_uuids(&current_fip_file.entry.uuid,
343*91f16700Schasinglulu 				&uuid_null) != 0));
344*91f16700Schasinglulu 
345*91f16700Schasinglulu 	if (found_file == 1) {
346*91f16700Schasinglulu 		/* All fine. Update entity info with file state and return. Set
347*91f16700Schasinglulu 		 * the file position to 0. The 'current_fip_file.entry' holds
348*91f16700Schasinglulu 		 * the base and size of the file.
349*91f16700Schasinglulu 		 */
350*91f16700Schasinglulu 		current_fip_file.file_pos = 0;
351*91f16700Schasinglulu 		entity->info = (uintptr_t)&current_fip_file;
352*91f16700Schasinglulu 	} else {
353*91f16700Schasinglulu 		/* Did not find the file in the FIP. */
354*91f16700Schasinglulu 		current_fip_file.entry.offset_address = 0;
355*91f16700Schasinglulu 		result = -ENOENT;
356*91f16700Schasinglulu 	}
357*91f16700Schasinglulu 
358*91f16700Schasinglulu  fip_file_open_close:
359*91f16700Schasinglulu 	io_close(backend_handle);
360*91f16700Schasinglulu 
361*91f16700Schasinglulu  fip_file_open_exit:
362*91f16700Schasinglulu 	return result;
363*91f16700Schasinglulu }
364*91f16700Schasinglulu 
365*91f16700Schasinglulu 
366*91f16700Schasinglulu /* Return the size of a file in package */
367*91f16700Schasinglulu static int fip_file_len(io_entity_t *entity, size_t *length)
368*91f16700Schasinglulu {
369*91f16700Schasinglulu 	assert(entity != NULL);
370*91f16700Schasinglulu 	assert(length != NULL);
371*91f16700Schasinglulu 
372*91f16700Schasinglulu 	*length =  ((fip_file_state_t *)entity->info)->entry.size;
373*91f16700Schasinglulu 
374*91f16700Schasinglulu 	return 0;
375*91f16700Schasinglulu }
376*91f16700Schasinglulu 
377*91f16700Schasinglulu 
378*91f16700Schasinglulu /* Read data from a file in package */
379*91f16700Schasinglulu static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
380*91f16700Schasinglulu 			  size_t *length_read)
381*91f16700Schasinglulu {
382*91f16700Schasinglulu 	int result;
383*91f16700Schasinglulu 	fip_file_state_t *fp;
384*91f16700Schasinglulu 	size_t file_offset;
385*91f16700Schasinglulu 	size_t bytes_read;
386*91f16700Schasinglulu 	uintptr_t backend_handle;
387*91f16700Schasinglulu 
388*91f16700Schasinglulu 	assert(entity != NULL);
389*91f16700Schasinglulu 	assert(length_read != NULL);
390*91f16700Schasinglulu 	assert(entity->info != (uintptr_t)NULL);
391*91f16700Schasinglulu 
392*91f16700Schasinglulu 	/* Open the backend, attempt to access the blob image */
393*91f16700Schasinglulu 	result = io_open(backend_dev_handle, backend_image_spec,
394*91f16700Schasinglulu 			 &backend_handle);
395*91f16700Schasinglulu 	if (result != 0) {
396*91f16700Schasinglulu 		WARN("Failed to open FIP (%i)\n", result);
397*91f16700Schasinglulu 		result = -ENOENT;
398*91f16700Schasinglulu 		goto fip_file_read_exit;
399*91f16700Schasinglulu 	}
400*91f16700Schasinglulu 
401*91f16700Schasinglulu 	fp = (fip_file_state_t *)entity->info;
402*91f16700Schasinglulu 
403*91f16700Schasinglulu 	/* Seek to the position in the FIP where the payload lives */
404*91f16700Schasinglulu 	file_offset = fp->entry.offset_address + fp->file_pos;
405*91f16700Schasinglulu 	result = io_seek(backend_handle, IO_SEEK_SET,
406*91f16700Schasinglulu 			 (signed long long)file_offset);
407*91f16700Schasinglulu 	if (result != 0) {
408*91f16700Schasinglulu 		WARN("fip_file_read: failed to seek\n");
409*91f16700Schasinglulu 		result = -ENOENT;
410*91f16700Schasinglulu 		goto fip_file_read_close;
411*91f16700Schasinglulu 	}
412*91f16700Schasinglulu 
413*91f16700Schasinglulu 	result = io_read(backend_handle, buffer, length, &bytes_read);
414*91f16700Schasinglulu 	if (result != 0) {
415*91f16700Schasinglulu 		/* We cannot read our data. Fail. */
416*91f16700Schasinglulu 		WARN("Failed to read payload (%i)\n", result);
417*91f16700Schasinglulu 		result = -ENOENT;
418*91f16700Schasinglulu 		goto fip_file_read_close;
419*91f16700Schasinglulu 	} else {
420*91f16700Schasinglulu 		/* Set caller length and new file position. */
421*91f16700Schasinglulu 		*length_read = bytes_read;
422*91f16700Schasinglulu 		fp->file_pos += bytes_read;
423*91f16700Schasinglulu 	}
424*91f16700Schasinglulu 
425*91f16700Schasinglulu /* Close the backend. */
426*91f16700Schasinglulu  fip_file_read_close:
427*91f16700Schasinglulu 	io_close(backend_handle);
428*91f16700Schasinglulu 
429*91f16700Schasinglulu  fip_file_read_exit:
430*91f16700Schasinglulu 	return result;
431*91f16700Schasinglulu }
432*91f16700Schasinglulu 
433*91f16700Schasinglulu 
434*91f16700Schasinglulu /* Close a file in package */
435*91f16700Schasinglulu static int fip_file_close(io_entity_t *entity)
436*91f16700Schasinglulu {
437*91f16700Schasinglulu 	/* Clear our current file pointer.
438*91f16700Schasinglulu 	 * If we had malloc() we would free() here.
439*91f16700Schasinglulu 	 */
440*91f16700Schasinglulu 	if (current_fip_file.entry.offset_address != 0U) {
441*91f16700Schasinglulu 		zeromem(&current_fip_file, sizeof(current_fip_file));
442*91f16700Schasinglulu 	}
443*91f16700Schasinglulu 
444*91f16700Schasinglulu 	/* Clear the Entity info. */
445*91f16700Schasinglulu 	entity->info = 0;
446*91f16700Schasinglulu 
447*91f16700Schasinglulu 	return 0;
448*91f16700Schasinglulu }
449*91f16700Schasinglulu 
450*91f16700Schasinglulu /* Exported functions */
451*91f16700Schasinglulu 
452*91f16700Schasinglulu /* Register the Firmware Image Package driver with the IO abstraction */
453*91f16700Schasinglulu int register_io_dev_fip(const io_dev_connector_t **dev_con)
454*91f16700Schasinglulu {
455*91f16700Schasinglulu 	int result;
456*91f16700Schasinglulu 	assert(dev_con != NULL);
457*91f16700Schasinglulu 
458*91f16700Schasinglulu 	/*
459*91f16700Schasinglulu 	 * Since dev_info isn't really used in io_register_device, always
460*91f16700Schasinglulu 	 * use the same device info at here instead.
461*91f16700Schasinglulu 	 */
462*91f16700Schasinglulu 	result = io_register_device(&dev_info_pool[0]);
463*91f16700Schasinglulu 	if (result == 0)
464*91f16700Schasinglulu 		*dev_con = &fip_dev_connector;
465*91f16700Schasinglulu 
466*91f16700Schasinglulu 	return result;
467*91f16700Schasinglulu }
468*91f16700Schasinglulu 
469*91f16700Schasinglulu /* Function to retrieve plat_toc_flags, previously saved in FIP dev */
470*91f16700Schasinglulu int fip_dev_get_plat_toc_flag(io_dev_info_t *dev_info, uint16_t *plat_toc_flag)
471*91f16700Schasinglulu {
472*91f16700Schasinglulu 	fip_dev_state_t *state;
473*91f16700Schasinglulu 
474*91f16700Schasinglulu 	assert(dev_info != NULL);
475*91f16700Schasinglulu 
476*91f16700Schasinglulu 	state = (fip_dev_state_t *)dev_info->info;
477*91f16700Schasinglulu 
478*91f16700Schasinglulu 	*plat_toc_flag =  state->plat_toc_flag;
479*91f16700Schasinglulu 
480*91f16700Schasinglulu 	return 0;
481*91f16700Schasinglulu }
482