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 */ 23static const char readstrm[] = { "Error reading %s from input stream" }; 24static const char seek[] = { "Set file position to %d failed" }; 25static const char isiz[] = { "Bad image packet size %d" }; 26static const char err_checksum[] = { "Checksum failed on %s" }; 27 28static 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 33static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" }; 34static 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 ************************************************************************ */ 56static 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 ************************************************************************* */ 88static 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 ************************************************************************* */ 139void *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 ************************************************************************* */ 232int 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 ************************************************************************* */ 272int 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 ************************************************************************* */ 383void 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