Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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 | |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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++) { |
Armando Uribe | 803cd75 | 2010-07-22 20:25:32 -0500 | [diff] [blame] | 105 | shp = (struct ldr_section_info *)&dlthis->sect_hdrs[sec]; |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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 = |
Armando Uribe | 803cd75 | 2010-07-22 20:25:32 -0500 | [diff] [blame] | 208 | (struct ldr_section_info *)&dlthis->sect_hdrs[sec]; |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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 |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 221 | * section_name Pointer to the string name of the section desired |
| 222 | * section_info Address of a section info structure pointer to be |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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 | ************************************************************************* */ |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 232 | int dload_get_section_info(void *minfo, const char *section_name, |
| 233 | const struct ldr_section_info **const section_info) |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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++) { |
Armando Uribe | 803cd75 | 2010-07-22 20:25:32 -0500 | [diff] [blame] | 244 | shp = (struct ldr_section_info *)&dlthis->sect_hdrs[sec]; |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 245 | if (strcmp(section_name, shp->name) == 0) { |
| 246 | *section_info = shp; |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 247 | return true; |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | return false; |
| 252 | } |
| 253 | |
| 254 | #define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 255 | |
| 256 | /************************************************************************** |
| 257 | * Procedure dload_get_section |
| 258 | * |
| 259 | * Parameters: |
| 260 | * minfo Handle from dload_module_open for this module |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 261 | * section_info Pointer to a section info structure for the desired |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 262 | * section |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 263 | * section_data Buffer to contain the section initialized data |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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, |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 273 | const struct ldr_section_info *section_info, |
| 274 | void *section_data) |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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; |
Rene Sapiens | 318b5df | 2010-07-09 21:24:05 -0500 | [diff] [blame] | 283 | s8 *dest = (s8 *) section_data; |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 284 | |
| 285 | dlthis = (struct dload_state *)minfo; |
| 286 | if (!dlthis) |
| 287 | return false; |
Armando Uribe | 803cd75 | 2010-07-22 20:25:32 -0500 | [diff] [blame] | 288 | sptr = (struct doff_scnhdr_t *)section_info; |
Omar Ramirez Luna | 26f8db7 | 2010-06-23 16:02:02 +0300 | [diff] [blame] | 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 | } |