1 /*
2  * getsection.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Copyright (C) 2005-2006 Texas Instruments, Inc.
7  *
8  * This package is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15  */
16 
17 #include <dspbridge/getsection.h>
18 #include "header.h"
19 
20 /*
21  * Error strings
22  */
23 static const char readstrm[] = { "Error reading %s from input stream" };
24 static const char seek[] = { "Set file position to %d failed" };
25 static const char isiz[] = { "Bad image packet size %d" };
26 static const char err_checksum[] = { "Checksum failed on %s" };
27 
28 static const char err_reloc[] = { "dload_get_section unable to read"
29 	    "sections containing relocation entries"
30 };
31 
32 #if BITS_PER_AU > BITS_PER_BYTE
33 static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
34 static const char stbl[] = { "Bad string table offset " FMT_UI32 };
35 #endif
36 
37 /************************************************************** */
38 /********************* SUPPORT FUNCTIONS ********************** */
39 /************************************************************** */
40 
41 #if BITS_PER_AU > BITS_PER_BYTE
42 /**************************************************************************
43  * Procedure unpack_sec_name
44  *
45  * Parameters:
46  *  dlthis		Handle from dload_module_open for this module
47  *	soffset	    Byte offset into the string table
48  *  dst         Place to store the expanded string
49  *
50  * Effect:
51  *	Stores a string from the string table into the destination, expanding
52  * it in the process.  Returns a pointer just past the end of the stored
53  * string on success, or NULL on failure.
54  *
55  ************************************************************************ */
unpack_sec_name(struct dload_state * dlthis,u32 soffset,char * dst)56 static char *unpack_sec_name(struct dload_state *dlthis, u32 soffset, char *dst)
57 {
58 	u8 tmp, *src;
59 
60 	if (soffset >= dlthis->dfile_hdr.df_scn_name_size) {
61 		dload_error(dlthis, stbl, soffset);
62 		return NULL;
63 	}
64 	src = (u8 *) dlthis->str_head +
65 	    (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
66 	if (soffset & 1)
67 		*dst++ = *src++;	/* only 1 character in first word */
68 	do {
69 		tmp = *src++;
70 		*dst = (tmp >> BITS_PER_BYTE)
71 		    if (!(*dst++))
72 			break;
73 	} while ((*dst++ = tmp & BYTE_MASK));
74 
75 	return dst;
76 }
77 
78 /**************************************************************************
79  * Procedure expand_sec_names
80  *
81  * Parameters:
82  *  dlthis		Handle from dload_module_open for this module
83  *
84  * Effect:
85  *    Allocates a buffer, unpacks and copies strings from string table into it.
86  * Stores a pointer to the buffer into a state variable.
87  ************************************************************************* */
expand_sec_names(struct dload_state * dlthis)88 static void expand_sec_names(struct dload_state *dlthis)
89 {
90 	char *xstrings, *curr, *next;
91 	u32 xsize;
92 	u16 sec;
93 	struct ldr_section_info *shp;
94 	/* assume worst-case size requirement */
95 	xsize = dlthis->dfile_hdr.df_max_str_len * dlthis->dfile_hdr.df_no_scns;
96 	xstrings = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, xsize);
97 	if (xstrings == NULL) {
98 		dload_error(dlthis, err_alloc, xsize);
99 		return;
100 	}
101 	dlthis->xstrings = xstrings;
102 	/* For each sec, copy and expand its name */
103 	curr = xstrings;
104 	for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
105 		shp = (struct ldr_section_info *)&dlthis->sect_hdrs[sec];
106 		next = unpack_sec_name(dlthis, *(u32 *) &shp->name, curr);
107 		if (next == NULL)
108 			break;	/* error */
109 		shp->name = curr;
110 		curr = next;
111 	}
112 }
113 
114 #endif
115 
116 /************************************************************** */
117 /********************* EXPORTED FUNCTIONS ********************* */
118 /************************************************************** */
119 
120 /**************************************************************************
121  * Procedure dload_module_open
122  *
123  * Parameters:
124  *	module	The input stream that supplies the module image
125  *	syms	Host-side malloc/free and error reporting functions.
126  *			Other methods are unused.
127  *
128  * Effect:
129  *	Reads header information from a dynamic loader module using the
130     specified
131  * stream object, and returns a handle for the module information.  This
132  * handle may be used in subsequent query calls to obtain information
133  * contained in the module.
134  *
135  * Returns:
136  *	NULL if an error is encountered, otherwise a module handle for use
137  * in subsequent operations.
138  ************************************************************************* */
dload_module_open(struct dynamic_loader_stream * module,struct dynamic_loader_sym * syms)139 void *dload_module_open(struct dynamic_loader_stream *module,
140 				    struct dynamic_loader_sym *syms)
141 {
142 	struct dload_state *dlthis;	/* internal state for this call */
143 	unsigned *dp, sz;
144 	u32 sec_start;
145 #if BITS_PER_AU <= BITS_PER_BYTE
146 	u16 sec;
147 #endif
148 
149 	/* Check that mandatory arguments are present */
150 	if (!module || !syms) {
151 		if (syms != NULL)
152 			dload_syms_error(syms, "Required parameter is NULL");
153 
154 		return NULL;
155 	}
156 
157 	dlthis = (struct dload_state *)
158 	    syms->dload_allocate(syms, sizeof(struct dload_state));
159 	if (!dlthis) {
160 		/* not enough storage */
161 		dload_syms_error(syms, "Can't allocate module info");
162 		return NULL;
163 	}
164 
165 	/* clear our internal state */
166 	dp = (unsigned *)dlthis;
167 	for (sz = sizeof(struct dload_state) / sizeof(unsigned);
168 	     sz > 0; sz -= 1)
169 		*dp++ = 0;
170 
171 	dlthis->strm = module;
172 	dlthis->mysym = syms;
173 
174 	/* read in the doff image and store in our state variable */
175 	dload_headers(dlthis);
176 
177 	if (!dlthis->dload_errcount)
178 		dload_strings(dlthis, true);
179 
180 	/* skip ahead past the unread portion of the string table */
181 	sec_start = sizeof(struct doff_filehdr_t) +
182 	    sizeof(struct doff_verify_rec_t) +
183 	    BYTE_TO_HOST(DOFF_ALIGN(dlthis->dfile_hdr.df_strtab_size));
184 
185 	if (dlthis->strm->set_file_posn(dlthis->strm, sec_start) != 0) {
186 		dload_error(dlthis, seek, sec_start);
187 		return NULL;
188 	}
189 
190 	if (!dlthis->dload_errcount)
191 		dload_sections(dlthis);
192 
193 	if (dlthis->dload_errcount) {
194 		dload_module_close(dlthis);	/* errors, blow off our state */
195 		dlthis = NULL;
196 		return NULL;
197 	}
198 #if BITS_PER_AU > BITS_PER_BYTE
199 	/* Expand all section names from the string table into the */
200 	/* state variable, and convert section names from a relative */
201 	/* string table offset to a pointers to the expanded string. */
202 	expand_sec_names(dlthis);
203 #else
204 	/* Convert section names from a relative string table offset */
205 	/* to a pointer into the string table. */
206 	for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
207 		struct ldr_section_info *shp =
208 		    (struct ldr_section_info *)&dlthis->sect_hdrs[sec];
209 		shp->name = dlthis->str_head + *(u32 *) &shp->name;
210 	}
211 #endif
212 
213 	return dlthis;
214 }
215 
216 /***************************************************************************
217  * Procedure dload_get_section_info
218  *
219  * Parameters:
220  *  minfo		Handle from dload_module_open for this module
221  *	section_name	Pointer to the string name of the section desired
222  *	section_info	Address of a section info structure pointer to be
223  *			initialized
224  *
225  * Effect:
226  *	Finds the specified section in the module information, and initializes
227  * the provided struct ldr_section_info pointer.
228  *
229  * Returns:
230  *	true for success, false for section not found
231  ************************************************************************* */
dload_get_section_info(void * minfo,const char * section_name,const struct ldr_section_info ** const section_info)232 int dload_get_section_info(void *minfo, const char *section_name,
233 			   const struct ldr_section_info **const section_info)
234 {
235 	struct dload_state *dlthis;
236 	struct ldr_section_info *shp;
237 	u16 sec;
238 
239 	dlthis = (struct dload_state *)minfo;
240 	if (!dlthis)
241 		return false;
242 
243 	for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) {
244 		shp = (struct ldr_section_info *)&dlthis->sect_hdrs[sec];
245 		if (strcmp(section_name, shp->name) == 0) {
246 			*section_info = shp;
247 			return true;
248 		}
249 	}
250 
251 	return false;
252 }
253 
254 #define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
255 
256 /**************************************************************************
257  * Procedure dload_get_section
258  *
259  * Parameters:
260  *  minfo		Handle from dload_module_open for this module
261  *	section_info	Pointer to a section info structure for the desired
262  *			section
263  *	section_data	Buffer to contain the section initialized data
264  *
265  * Effect:
266  *	Copies the initialized data for the specified section into the
267  * supplied buffer.
268  *
269  * Returns:
270  *	true for success, false for section not found
271  ************************************************************************* */
dload_get_section(void * minfo,const struct ldr_section_info * section_info,void * section_data)272 int dload_get_section(void *minfo,
273 		      const struct ldr_section_info *section_info,
274 		      void *section_data)
275 {
276 	struct dload_state *dlthis;
277 	u32 pos;
278 	struct doff_scnhdr_t *sptr = NULL;
279 	s32 nip;
280 	struct image_packet_t ipacket;
281 	s32 ipsize;
282 	u32 checks;
283 	s8 *dest = (s8 *) section_data;
284 
285 	dlthis = (struct dload_state *)minfo;
286 	if (!dlthis)
287 		return false;
288 	sptr = (struct doff_scnhdr_t *)section_info;
289 	if (sptr == NULL)
290 		return false;
291 
292 	/* skip ahead to the start of the first packet */
293 	pos = BYTE_TO_HOST(DOFF_ALIGN((u32) sptr->ds_first_pkt_offset));
294 	if (dlthis->strm->set_file_posn(dlthis->strm, pos) != 0) {
295 		dload_error(dlthis, seek, pos);
296 		return false;
297 	}
298 
299 	nip = sptr->ds_nipacks;
300 	while ((nip -= 1) >= 0) {	/* for each packet */
301 		/* get the fixed header bits */
302 		if (dlthis->strm->read_buffer(dlthis->strm, &ipacket,
303 					      IPH_SIZE) != IPH_SIZE) {
304 			dload_error(dlthis, readstrm, "image packet");
305 			return false;
306 		}
307 		/* reorder the header if need be */
308 		if (dlthis->reorder_map)
309 			dload_reorder(&ipacket, IPH_SIZE, dlthis->reorder_map);
310 
311 		/* Now read the packet image bits. Note: round the size up to
312 		 * the next multiple of 4 bytes; this is what checksum
313 		 * routines want. */
314 		ipsize = BYTE_TO_HOST(DOFF_ALIGN(ipacket.packet_size));
315 		if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
316 			dload_error(dlthis, isiz, ipsize);
317 			return false;
318 		}
319 		if (dlthis->strm->read_buffer
320 		    (dlthis->strm, dest, ipsize) != ipsize) {
321 			dload_error(dlthis, readstrm, "image packet");
322 			return false;
323 		}
324 		/* reorder the bytes if need be */
325 #if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
326 		if (dlthis->reorder_map)
327 			dload_reorder(dest, ipsize, dlthis->reorder_map);
328 
329 		checks = dload_checksum(dest, ipsize);
330 #else
331 		if (dlthis->dfile_hdr.df_byte_reshuffle !=
332 		    TARGET_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
333 			/* put image bytes in big-endian order, not PC order */
334 			dload_reorder(dest, ipsize,
335 				      TARGET_ORDER(dlthis->
336 						dfile_hdr.df_byte_reshuffle));
337 		}
338 #if TARGET_AU_BITS > 8
339 		checks = dload_reverse_checksum16(dest, ipsize);
340 #else
341 		checks = dload_reverse_checksum(dest, ipsize);
342 #endif
343 #endif
344 		checks += dload_checksum(&ipacket, IPH_SIZE);
345 
346 		/* NYI: unable to handle relocation entries here.  Reloc
347 		 * entries referring to fields that span the packet boundaries
348 		 * may result in packets of sizes that are not multiple of
349 		 * 4 bytes. Our checksum implementation works on 32-bit words
350 		 * only. */
351 		if (ipacket.num_relocs != 0) {
352 			dload_error(dlthis, err_reloc, ipsize);
353 			return false;
354 		}
355 
356 		if (~checks) {
357 			dload_error(dlthis, err_checksum, "image packet");
358 			return false;
359 		}
360 
361 		/*Advance destination ptr by the size of the just-read packet */
362 		dest += ipsize;
363 	}
364 
365 	return true;
366 }
367 
368 /***************************************************************************
369  * Procedure dload_module_close
370  *
371  * Parameters:
372  *  minfo		Handle from dload_module_open for this module
373  *
374  * Effect:
375  *	Releases any storage associated with the module handle.  On return,
376  * the module handle is invalid.
377  *
378  * Returns:
379  *	Zero for success. On error, the number of errors detected is returned.
380  * Individual errors are reported using syms->error_report(), where syms was
381  * an argument to dload_module_open
382  ************************************************************************* */
dload_module_close(void * minfo)383 void dload_module_close(void *minfo)
384 {
385 	struct dload_state *dlthis;
386 
387 	dlthis = (struct dload_state *)minfo;
388 	if (!dlthis)
389 		return;
390 
391 	if (dlthis->str_head)
392 		dlthis->mysym->dload_deallocate(dlthis->mysym,
393 						dlthis->str_head);
394 
395 	if (dlthis->sect_hdrs)
396 		dlthis->mysym->dload_deallocate(dlthis->mysym,
397 						dlthis->sect_hdrs);
398 
399 #if BITS_PER_AU > BITS_PER_BYTE
400 	if (dlthis->xstrings)
401 		dlthis->mysym->dload_deallocate(dlthis->mysym,
402 						dlthis->xstrings);
403 
404 #endif
405 
406 	dlthis->mysym->dload_deallocate(dlthis->mysym, dlthis);
407 }
408