tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / staging / tidspbridge / dynload / getsection.c
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  ************************************************************************ */
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  ************************************************************************* */
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  ************************************************************************* */
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  ************************************************************************* */
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  ************************************************************************* */
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  ************************************************************************* */
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 }