Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
getsection.c
Go to the documentation of this file.
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  ************************************************************************* */
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 */
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 !=
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 }