1 /* IBM_PROLOG_BEGIN_TAG */
2 /* This is an automatically generated prolog. */
3 /* */
4 /* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/sbe_xip_image.c $ */
5 /* */
6 /* OpenPOWER HostBoot Project */
7 /* */
8 /* Contributors Listed Below - COPYRIGHT 2012,2015 */
9 /* [+] International Business Machines Corp. */
10 /* */
11 /* */
12 /* Licensed under the Apache License, Version 2.0 (the "License"); */
13 /* you may not use this file except in compliance with the License. */
14 /* You may obtain a copy of the License at */
15 /* */
16 /* http://www.apache.org/licenses/LICENSE-2.0 */
17 /* */
18 /* Unless required by applicable law or agreed to in writing, software */
19 /* distributed under the License is distributed on an "AS IS" BASIS, */
20 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
21 /* implied. See the License for the specific language governing */
22 /* permissions and limitations under the License. */
23 /* */
24 /* IBM_PROLOG_END_TAG */
25 // $Id: sbe_xip_image.c,v 1.31 2015/07/29 23:40:06 cmolsen Exp $
26 // $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/sbe/sbe_xip_image.c,v $
27 //-----------------------------------------------------------------------------
28 // *! (C) Copyright International Business Machines Corp. 2011
29 // *! All Rights Reserved -- Property of IBM
30 // *! *** ***
31 //-----------------------------------------------------------------------------
32 // *! OWNER NAME: Bishop Brock Email: bcbrock@us.ibm.com
33 //------------------------------------------------------------------------------
34
35 /// \file sbe_xip_image.c
36 /// \brief APIs for validating, normalizing, searching and manipulating
37 /// SBE-XIP images.
38 ///
39 /// The background, APIs and implementation details are documented in the
40 /// document "SBE-XIP Binary format" currently available at this link:
41 ///
42 /// - https://mcdoc.boeblingen.de.ibm.com/out/out.ViewDocument.php?documentid=2678
43 ///
44 /// \bug The sbe_xip_validate() API should be carefully reviewed to ensure
45 /// that validating even a corrupt image can not lead to a segfault, i.e., to
46 /// ensure that no memory outside of the putative bounds of the image is ever
47 /// referenced during validation.
48
49 #ifndef PLIC_MODULE
50 #include <stddef.h>
51 #include <stdint.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #endif // PLIC_MODULE
55
56 #include <stddef.h>
57 #include <stdint.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include "sbe_xip_image.h"
61
62
63 ////////////////////////////////////////////////////////////////////////////
64 // Local Functions
65 ////////////////////////////////////////////////////////////////////////////
66
67 // PHYP has their own way of implementing the <string.h> functions. PHYP also
68 // does not allow static functions or data, so all of the XIP_STATIC functions
69 // defined here are global to PHYP.
70
71 #ifdef PPC_HYP
72
73 #ifdef PLIC_MODULE
74
75 #define strcpy(dest, src) hvstrcpy(dest, src)
76 #define strlen(s) hvstrlen(s)
77 #define strcmp(s1, s2) hvstrcmp(s1, s2)
78 #endif //PLIC_MODULE
79
80 #define XIP_STATIC
81
82 #else // PPC_HYP
83
84 #define XIP_STATIC static
85
86 #endif // PPC_HYP
87
88
89 #ifdef DEBUG_SBE_XIP_IMAGE
90
91 // Debugging support, normally disabled. All of the formatted I/O you see in
92 // the code is effectively under this switch.
93
94 #ifdef __FAPI
95
96 #include "fapi.H"
97 #define fprintf(stream, ...) FAPI_ERR(__VA_ARGS__)
98 #define printf(...) FAPI_INF(__VA_ARGS__)
99 #define TRACE_NEWLINE ""
100
101 #else // __FAPI
102
103 #include <stdio.h>
104 #define TRACE_NEWLINE "\n"
105
106 #endif // __FAPI
107
108 // Portable formatting of uint64_t. The ISO C99 standard requires
109 // __STDC_FORMAT_MACROS to be defined in order for PRIx64 etc. to be defined.
110
111 #define __STDC_FORMAT_MACROS
112 #include <inttypes.h>
113
114 #define F0x016llx "0x%016" PRIx64
115 #define F0x012llx "0x%012" PRIx64
116
117 XIP_STATIC SBE_XIP_ERROR_STRINGS(sbe_xip_error_strings);
118
119 #define TRACE_ERROR(x) \
120 ({ \
121 fprintf(stderr, "%s:%d : Returning error code %d : %s" TRACE_NEWLINE, \
122 __FILE__, __LINE__, (x), \
123 SBE_XIP_ERROR_STRING(sbe_xip_error_strings, (x))); \
124 (x); \
125 })
126
127 #define TRACE_ERRORX(x, ...) \
128 ({ \
129 TRACE_ERROR(x); \
130 fprintf(stderr, ##__VA_ARGS__); \
131 (x); \
132 })
133
134
135 // Uncomment these if required for debugging, otherwise we get warnings from
136 // GCC as they are not otherwise used.
137
138 #if 0
139
140 XIP_STATIC uint32_t xipRevLe32(const uint32_t i_x);
141
142 XIP_STATIC SBE_XIP_TYPE_STRINGS(type_strings);
143
144 XIP_STATIC void
145 dumpToc(int index, SbeXipToc* toc)
146 {
147 printf("TOC entry %d @ %p\n"
148 " iv_id = 0x%08x\n"
149 " iv_data = 0x%08x\n"
150 " iv_type = %s\n"
151 " iv_section = 0x%02x\n"
152 " iv_elements = %d\n",
153 index, toc,
154 xipRevLe32(toc->iv_id),
155 xipRevLe32(toc->iv_data),
156 SBE_XIP_TYPE_STRING(type_strings, toc->iv_type),
157 toc->iv_section,
158 toc->iv_elements);
159 }
160
161 #endif
162
163 #if 0
164
165 XIP_STATIC void
166 dumpItem(SbeXipItem* item)
167 {
168 printf("SbeXipItem @ %p\n"
169 " iv_toc = %p\n"
170 " iv_address = " F0x016llx "\n"
171 " iv_imageData = %p\n"
172 " iv_id = %s\n"
173 " iv_type = %s\n"
174 " iv_elements = %d\n",
175 item,
176 item->iv_toc,
177 item->iv_address,
178 item->iv_imageData,
179 item->iv_id,
180 SBE_XIP_TYPE_STRING(type_strings, item->iv_type),
181 item->iv_elements);
182 dumpToc(-1, item->iv_toc);
183 }
184
185 #endif /* 0 */
186
187 XIP_STATIC void
dumpSectionTable(const void * i_image)188 dumpSectionTable(const void* i_image)
189 {
190 int i, rc;
191 SbeXipSection section;
192
193 printf("Section table dump of image @ %p\n"
194 " Entry Offset Size\n"
195 "-------------------------------\n",
196 i_image);
197
198 for (i = 0; i < SBE_XIP_SECTIONS; i++) {
199 rc = sbe_xip_get_section(i_image, i, §ion);
200 if (rc) {
201 printf(">>> dumpSectionTable got error at entry %d : %s\n",
202 i, SBE_XIP_ERROR_STRING(sbe_xip_error_strings, rc));
203 break;
204 }
205 printf("%7d 0x%08x 0x%08x\n",
206 i, section.iv_offset, section.iv_size);
207 }
208 }
209
210 #else
211
212 #define TRACE_ERROR(x) (x)
213 #define TRACE_ERRORX(x, ...) (x)
214 #define dumpToc(...)
215 #define dumpItem(...)
216 #define dumpSectionTable(...)
217
218 #endif
219
220
221 // Note: For maximum flexibility we provide private versions of
222 // endian-conversion routines rather than counting on a system-specific header
223 // to provide these.
224
225 /// Byte-reverse a 16-bit integer if on a little-endian machine
226
227 XIP_STATIC uint16_t
xipRevLe16(const uint16_t i_x)228 xipRevLe16(const uint16_t i_x)
229 {
230 uint16_t rx;
231
232 #ifndef _BIG_ENDIAN
233 uint8_t *pix = (uint8_t*)(&i_x);
234 uint8_t *prx = (uint8_t*)(&rx);
235
236 prx[0] = pix[1];
237 prx[1] = pix[0];
238 #else
239 rx = i_x;
240 #endif
241
242 return rx;
243 }
244
245
246 /// Byte-reverse a 32-bit integer if on a little-endian machine
247
248 XIP_STATIC uint32_t
xipRevLe32(const uint32_t i_x)249 xipRevLe32(const uint32_t i_x)
250 {
251 uint32_t rx;
252
253 #ifndef _BIG_ENDIAN
254 uint8_t *pix = (uint8_t*)(&i_x);
255 uint8_t *prx = (uint8_t*)(&rx);
256
257 prx[0] = pix[3];
258 prx[1] = pix[2];
259 prx[2] = pix[1];
260 prx[3] = pix[0];
261 #else
262 rx = i_x;
263 #endif
264
265 return rx;
266 }
267
268
269 /// Byte-reverse a 64-bit integer if on a little-endian machine
270
271 XIP_STATIC uint64_t
xipRevLe64(const uint64_t i_x)272 xipRevLe64(const uint64_t i_x)
273 {
274 uint64_t rx;
275
276 #ifndef _BIG_ENDIAN
277 uint8_t *pix = (uint8_t*)(&i_x);
278 uint8_t *prx = (uint8_t*)(&rx);
279
280 prx[0] = pix[7];
281 prx[1] = pix[6];
282 prx[2] = pix[5];
283 prx[3] = pix[4];
284 prx[4] = pix[3];
285 prx[5] = pix[2];
286 prx[6] = pix[1];
287 prx[7] = pix[0];
288 #else
289 rx = i_x;
290 #endif
291
292 return rx;
293 }
294
295
296 /// What is the image link address?
297
298 XIP_STATIC uint64_t
xipLinkAddress(const void * i_image)299 xipLinkAddress(const void* i_image)
300 {
301 return xipRevLe64(((SbeXipHeader*)i_image)->iv_linkAddress);
302 }
303
304
305 /// What is the image size?
306
307 XIP_STATIC uint32_t
xipImageSize(const void * i_image)308 xipImageSize(const void* i_image)
309 {
310 return xipRevLe32(((SbeXipHeader*)i_image)->iv_imageSize);
311 }
312
313
314 /// Set the image size
315
316 XIP_STATIC void
xipSetImageSize(void * io_image,const size_t i_size)317 xipSetImageSize(void* io_image, const size_t i_size)
318 {
319 ((SbeXipHeader*)io_image)->iv_imageSize = xipRevLe32(i_size);
320 }
321
322
323 /// Re-establish the required final alignment
324
325 XIP_STATIC void
xipFinalAlignment(void * io_image)326 xipFinalAlignment(void* io_image)
327 {
328 uint32_t size;
329
330 size = xipImageSize(io_image);
331
332 if ((size % SBE_XIP_FINAL_ALIGNMENT) != 0) {
333 xipSetImageSize(io_image,
334 size + (SBE_XIP_FINAL_ALIGNMENT -
335 (size % SBE_XIP_FINAL_ALIGNMENT)));
336 }
337 }
338
339
340 /// Compute a host address from an image address and offset
341
342 XIP_STATIC void*
xipHostAddressFromOffset(const void * i_image,const uint32_t offset)343 xipHostAddressFromOffset(const void* i_image, const uint32_t offset)
344 {
345 return (void*)((unsigned long)i_image + offset);
346 }
347
348
349 /// Convert a PORE address to a host address
350
351 XIP_STATIC void*
xipPore2Host(const void * i_image,const uint64_t i_poreAddress)352 xipPore2Host(const void* i_image, const uint64_t i_poreAddress)
353 {
354 return xipHostAddressFromOffset(i_image,
355 i_poreAddress - xipLinkAddress(i_image));
356 }
357
358
359 XIP_STATIC int
xipValidatePoreAddress(const void * i_image,const uint64_t i_poreAddress,const uint32_t size)360 xipValidatePoreAddress(const void* i_image,
361 const uint64_t i_poreAddress,
362 const uint32_t size)
363 {
364 int rc;
365
366 if ((i_poreAddress < xipLinkAddress(i_image)) ||
367 (i_poreAddress > (xipLinkAddress(i_image) +
368 xipImageSize(i_image) -
369 size))) {
370 rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT,
371 "The PORE address " F0x012llx
372 " is outside the bounds "
373 "of the image ("
374 F0x012llx ":" F0x012llx
375 ") for %u-byte access.\n",
376 i_poreAddress,
377 xipLinkAddress(i_image),
378 xipLinkAddress(i_image) + xipImageSize(i_image) - 1,
379 size);
380 } else {
381 rc = 0;
382 }
383 return rc;
384 }
385
386
387 /// Get the magic number from the image
388
389 XIP_STATIC uint64_t
xipMagic(const void * i_image)390 xipMagic(const void* i_image)
391 {
392 return xipRevLe64(((SbeXipHeader*)i_image)->iv_magic);
393 }
394
395
396 /// Get the header version from the image
397
398 XIP_STATIC uint8_t
xipHeaderVersion(const void * i_image)399 xipHeaderVersion(const void* i_image)
400 {
401 return ((SbeXipHeader*)i_image)->iv_headerVersion;
402 }
403
404
405 /// Has the image been normalized?
406
407 XIP_STATIC uint8_t
xipNormalized(const void * i_image)408 xipNormalized(const void* i_image)
409 {
410 return ((SbeXipHeader*)i_image)->iv_normalized;
411 }
412
413
414 /// Has the image TOC been sorted?
415
416 XIP_STATIC uint8_t
xipSorted(const void * i_image)417 xipSorted(const void* i_image)
418 {
419 return ((SbeXipHeader*)i_image)->iv_tocSorted;
420 }
421
422
423 /// A quick check that the image exists, has the correct magic and header
424 /// version, and optionally is normalized.
425
426 XIP_STATIC int
xipQuickCheck(const void * i_image,const int i_normalizationRequired)427 xipQuickCheck(const void* i_image, const int i_normalizationRequired)
428 {
429 int rc;
430
431 do {
432 rc = 0;
433
434 if (i_image == 0) {
435 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
436 "Image pointer is NULL (0)\n");
437 break;
438 }
439 if ((xipMagic(i_image) >> 32) != SBE_XIP_MAGIC) {
440 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
441 "Magic number mismatch; Found "
442 "" F0x016llx ", expected 0x%08x........\n",
443 xipMagic(i_image), SBE_XIP_MAGIC);
444 break;
445 }
446 if ((xipHeaderVersion(i_image)) != SBE_XIP_HEADER_VERSION) {
447 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
448 "Header version mismatch; Expecting %d, "
449 "found %d\n",
450 SBE_XIP_HEADER_VERSION,
451 xipHeaderVersion(i_image));
452 break;
453 }
454 if (i_normalizationRequired && !xipNormalized(i_image)) {
455 rc = TRACE_ERRORX(SBE_XIP_NOT_NORMALIZED,
456 "Image not normalized\n");
457 break;
458 }
459 } while(0);
460
461 return rc;
462 }
463
464
465 /// Convert a 32-bit relocatable offset to a full PORE 48-bit address
466
467 XIP_STATIC uint64_t
xipFullAddress(const void * i_image,uint32_t offset)468 xipFullAddress(const void* i_image, uint32_t offset)
469 {
470 return (xipLinkAddress(i_image) & 0x0000ffff00000000ull) + offset;
471 }
472
473
474 /// Translate a section table entry
475
476 XIP_STATIC void
xipTranslateSection(SbeXipSection * o_dest,const SbeXipSection * i_src)477 xipTranslateSection(SbeXipSection* o_dest, const SbeXipSection* i_src)
478 {
479 #ifndef _BIG_ENDIAN
480
481 #if SBE_XIP_HEADER_VERSION != 8
482 #error This code assumes the SBE-XIP header version 8 layout
483 #endif
484
485 o_dest->iv_offset = xipRevLe32(i_src->iv_offset);
486 o_dest->iv_size = xipRevLe32(i_src->iv_size);
487 o_dest->iv_alignment = i_src->iv_alignment;
488 o_dest->iv_reserved8[0] = 0;
489 o_dest->iv_reserved8[1] = 0;
490 o_dest->iv_reserved8[2] = 0;
491 #else
492 if (o_dest != i_src) {
493 *o_dest = *i_src;
494 }
495 #endif /* _BIG_ENDIAN */
496 }
497
498
499 /// Translate a TOC entry
500
501 XIP_STATIC void
xipTranslateToc(SbeXipToc * o_dest,SbeXipToc * i_src)502 xipTranslateToc(SbeXipToc* o_dest, SbeXipToc* i_src)
503 {
504 #ifndef _BIG_ENDIAN
505
506 #if SBE_XIP_HEADER_VERSION != 8
507 #error This code assumes the SBE-XIP header version 8 layout
508 #endif
509
510 o_dest->iv_id = xipRevLe32(i_src->iv_id);
511 o_dest->iv_data = xipRevLe32(i_src->iv_data);
512 o_dest->iv_type = i_src->iv_type;
513 o_dest->iv_section = i_src->iv_section;
514 o_dest->iv_elements = i_src->iv_elements;
515 o_dest->iv_pad = 0;
516 #else
517 if (o_dest != i_src) {
518 *o_dest = *i_src;
519 }
520 #endif /* _BIG_ENDIAN */
521 }
522
523
524 /// Find the final (highest-address) section of the image
525
526 XIP_STATIC int
xipFinalSection(const void * i_image,int * o_sectionId)527 xipFinalSection(const void* i_image, int* o_sectionId)
528 {
529 int i, rc, found;
530 uint32_t offset;
531 SbeXipHeader hostHeader;
532
533 sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image);
534
535 found = 0;
536 offset = 0;
537 *o_sectionId = 0; /* Make GCC -O3 happy */
538 for (i = 0; i < SBE_XIP_SECTIONS; i++) {
539 if ((hostHeader.iv_section[i].iv_size != 0) &&
540 (hostHeader.iv_section[i].iv_offset >= offset)) {
541 *o_sectionId = i;
542 offset = hostHeader.iv_section[i].iv_offset;
543 found = 1;
544 }
545 }
546 if (!found) {
547 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, "The image is empty\n");
548 } else {
549 rc = 0;
550 }
551 return rc;
552 }
553
554
555 /// Return a pointer to an image-format section table entry
556
557 XIP_STATIC int
xipGetSectionPointer(const void * i_image,const int i_sectionId,SbeXipSection ** o_imageSection)558 xipGetSectionPointer(const void* i_image,
559 const int i_sectionId,
560 SbeXipSection** o_imageSection)
561 {
562 int rc;
563
564 if ((i_sectionId < 0) || (i_sectionId >= SBE_XIP_SECTIONS)) {
565 rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
566 } else {
567 *o_imageSection =
568 &(((SbeXipHeader*)i_image)->iv_section[i_sectionId]);
569 rc = 0;
570 }
571 return rc;
572 }
573
574
575 /// Restore a section table entry from host format to image format.
576
577 XIP_STATIC int
xipPutSection(const void * i_image,const int i_sectionId,SbeXipSection * i_hostSection)578 xipPutSection(const void* i_image,
579 const int i_sectionId,
580 SbeXipSection* i_hostSection)
581 {
582 int rc;
583 SbeXipSection *imageSection = NULL;
584
585 rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection);
586
587 if (!rc) {
588 xipTranslateSection(imageSection, i_hostSection);
589 }
590
591 return rc;
592 }
593
594
595 /// Set the offset of a section
596
597 XIP_STATIC int
xipSetSectionOffset(void * io_image,const int i_section,const uint32_t i_offset)598 xipSetSectionOffset(void* io_image, const int i_section,
599 const uint32_t i_offset)
600 {
601 SbeXipSection* section = NULL;
602 int rc;
603
604 rc = xipGetSectionPointer(io_image, i_section, §ion);
605 if (!rc) {
606 section->iv_offset = xipRevLe32(i_offset);
607 }
608 return rc;
609 }
610
611
612 /// Set the size of a section
613
614 XIP_STATIC int
xipSetSectionSize(void * io_image,const int i_section,const uint32_t i_size)615 xipSetSectionSize(void* io_image, const int i_section, const uint32_t i_size)
616 {
617 SbeXipSection* section = NULL;
618 int rc;
619
620 rc = xipGetSectionPointer(io_image, i_section, §ion);
621 if (!rc) {
622 section->iv_size = xipRevLe32(i_size);
623 }
624 return rc;
625 }
626
627
628 /// Translate a PORE address in the image to a section and offset
629
630 // We first check to be sure that the PORE address is contained in the image,
631 // using the full 48-bit form. Then we scan the section table to see which
632 // section contains the address - if none then the image is corrupted. We can
633 // (must) use the 32-bit offset form of the address here.
634
635 XIP_STATIC int
xipPore2Section(const void * i_image,const uint64_t i_poreAddress,int * o_section,uint32_t * o_offset)636 xipPore2Section(const void* i_image,
637 const uint64_t i_poreAddress,
638 int* o_section,
639 uint32_t* o_offset)
640 {
641 int rc, sectionId;
642 SbeXipSection section;
643 uint32_t addressOffset;
644
645 do {
646 rc = 0;
647
648 if ((i_poreAddress < xipLinkAddress(i_image)) ||
649 (i_poreAddress >
650 (xipLinkAddress(i_image) + xipImageSize(i_image)))) {
651 rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT,
652 "pore2section: The i_poreAddress argument "
653 "(" F0x016llx ")\nis outside the bounds of the "
654 "image (" F0x016llx ":" F0x016llx ")\n",
655 i_poreAddress,
656 xipLinkAddress(i_image),
657 xipLinkAddress(i_image) + xipImageSize(i_image));
658 break;
659 }
660
661 addressOffset = (i_poreAddress - xipLinkAddress(i_image)) & 0xffffffff;
662
663 for (sectionId = 0; sectionId < SBE_XIP_SECTIONS; sectionId++) {
664 rc = sbe_xip_get_section(i_image, sectionId, §ion);
665 if (rc) {
666 rc = TRACE_ERROR(SBE_XIP_BUG); /* Can't happen */
667 break;
668 }
669 if ((section.iv_size != 0) &&
670 (addressOffset >= section.iv_offset) &&
671 (addressOffset < (section.iv_offset + section.iv_size))) {
672 break;
673 }
674 }
675 if (rc) break;
676
677 if (sectionId == SBE_XIP_SECTIONS) {
678 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
679 "Error processing PORE address " F0x016llx ". "
680 "The address is not mapped in any section.\n"
681 "A section table dump appears below\n",
682 i_poreAddress);
683 dumpSectionTable(i_image);
684 break;
685 }
686
687 *o_section = sectionId;
688 *o_offset = addressOffset - section.iv_offset;
689
690 } while(0);
691
692 return rc;
693 }
694
695
696 /// Get the information required to search the TOC.
697 ///
698 /// All return values are optional.
699
700 XIP_STATIC int
xipGetToc(void * i_image,SbeXipToc ** o_toc,size_t * o_entries,int * o_sorted,char ** o_strings)701 xipGetToc(void* i_image,
702 SbeXipToc** o_toc,
703 size_t* o_entries,
704 int* o_sorted,
705 char** o_strings)
706 {
707 int rc;
708 SbeXipSection tocSection, stringsSection;
709
710 do {
711 rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_TOC, &tocSection);
712 if (rc) break;
713
714 rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_STRINGS,
715 &stringsSection);
716 if (rc) break;
717
718 if (o_toc) {
719 *o_toc = (SbeXipToc*)((uint8_t*)i_image + tocSection.iv_offset);
720 }
721 if (o_entries) {
722 *o_entries = tocSection.iv_size / sizeof(SbeXipToc);
723 }
724 if (o_sorted) {
725 *o_sorted = xipSorted(i_image);
726 }
727 if (o_strings) {
728 *o_strings = (char*)i_image + stringsSection.iv_offset;
729 }
730 } while (0);
731 return rc;
732 }
733
734
735 /// Compare two normalized TOC entries for sorting.
736
737 XIP_STATIC int
xipCompareToc(const SbeXipToc * i_a,const SbeXipToc * i_b,const char * i_strings)738 xipCompareToc(const SbeXipToc* i_a, const SbeXipToc* i_b,
739 const char* i_strings)
740 {
741 return strcmp(i_strings + xipRevLe32(i_a->iv_id),
742 i_strings + xipRevLe32(i_b->iv_id));
743 }
744
745
746 /// Iterative quicksort of the TOC
747
748 // Note: The stack requirement is limited to 256 bytes + minor local storage.
749
750 XIP_STATIC void
xipQuickSort(SbeXipToc * io_toc,int i_left,int i_right,const char * i_strings)751 xipQuickSort(SbeXipToc* io_toc, int i_left, int i_right,
752 const char* i_strings)
753 {
754 int i, j, left, right, sp;
755 SbeXipToc pivot, temp;
756 uint32_t stack[64];
757
758 sp = 0;
759 stack[sp++] = i_left;
760 stack[sp++] = i_right;
761
762 while (sp) {
763
764 right = stack[--sp];
765 left = stack[--sp];
766
767 i = left;
768 j = right;
769
770 pivot = io_toc[(i + j) / 2];
771
772 while (i <= j) {
773 while (xipCompareToc(&(io_toc[i]), &pivot, i_strings) < 0) {
774 i++;
775 }
776 while (xipCompareToc(&(io_toc[j]), &pivot, i_strings) > 0) {
777 j--;
778 }
779 if (i <= j) {
780 temp = io_toc[i];
781 io_toc[i] = io_toc[j];
782 io_toc[j] = temp;
783 i++;
784 j--;
785 }
786 }
787 if (left < j) {
788 stack[sp++] = left;
789 stack[sp++] = j;
790 }
791 if (i < right) {
792 stack[sp++] = i;
793 stack[sp++] = right;
794 }
795 }
796 }
797
798
799 /// TOC linear search
800
801 XIP_STATIC int
xipLinearSearch(void * i_image,const char * i_id,SbeXipToc ** o_entry)802 xipLinearSearch(void* i_image, const char* i_id, SbeXipToc** o_entry)
803 {
804 int rc;
805 SbeXipToc *imageToc, hostToc;
806 size_t entries;
807 char* strings;
808
809 *o_entry = 0;
810 rc = xipGetToc(i_image, &imageToc, &entries, 0, &strings);
811 if (!rc) {
812 for (; entries; entries--, imageToc++) {
813 xipTranslateToc(&hostToc, imageToc);
814 if (strcmp(i_id, strings + hostToc.iv_id) == 0) {
815 break;
816 }
817 }
818 if (entries) {
819 *o_entry = imageToc;
820 rc = 0;
821 } else {
822 *o_entry = 0;
823 rc = TRACE_ERROR(SBE_XIP_ITEM_NOT_FOUND);
824 }
825 }
826 return rc;
827 }
828
829
830 /// A classic binary search of a (presumed) sorted array
831
832 XIP_STATIC int
xipBinarySearch(void * i_image,const char * i_id,SbeXipToc ** o_entry)833 xipBinarySearch(void* i_image, const char* i_id, SbeXipToc** o_entry)
834 {
835 int rc;
836 SbeXipToc *imageToc;
837 size_t entries;
838 char* strings;
839 int sorted, left, right, next, sort;
840
841 do {
842 *o_entry = 0;
843
844 rc = xipGetToc(i_image, &imageToc, &entries, &sorted, &strings);
845 if (rc) break;
846
847 if (!sorted) {
848 rc = TRACE_ERROR(SBE_XIP_BUG);
849 break;
850 }
851
852 left = 0;
853 right = entries - 1;
854 while (left <= right) {
855 next = (left + right) / 2;
856 sort = strcmp(i_id, strings + xipRevLe32(imageToc[next].iv_id));
857 if (sort == 0) {
858 *o_entry = &(imageToc[next]);
859 break;
860 } else if (sort < 0) {
861 right = next - 1;
862 } else {
863 left = next + 1;
864 }
865 }
866 if (*o_entry == 0) {
867 rc = TRACE_ERROR(SBE_XIP_ITEM_NOT_FOUND);
868 break;
869 }
870 } while (0);
871 return rc;
872 }
873
874
875 /// Validate a TOC entry as a mapping function
876 ///
877 /// The TOC is validated by searching for the entry, which will uncover
878 /// duplicate entries or problems with sorting/searching.
879
880 XIP_STATIC int
xipValidateTocEntry(void * io_image,const SbeXipItem * i_item,void * io_arg)881 xipValidateTocEntry(void* io_image, const SbeXipItem* i_item, void* io_arg)
882 {
883 int rc;
884 SbeXipItem found;
885
886 (void)io_arg;
887
888 do {
889 rc = sbe_xip_find(io_image, i_item->iv_id, &found);
890 if (rc) {
891 rc = TRACE_ERRORX(rc, "TOC entry for %s not found\n",
892 i_item->iv_id);
893 } else if (found.iv_toc != i_item->iv_toc) {
894 rc = TRACE_ERRORX(SBE_XIP_TOC_ERROR,
895 "Duplicate TOC entry for '%s'\n", i_item->iv_id);
896 }
897 break;
898 } while (0);
899 return rc;
900 }
901
902
903 // This is the FNV-1a hash, used for hashing symbol names in the .fixed
904 // section into 32-bit hashes for the mini-TOC.
905
906 // According to the authors:
907
908 // "FNV hash algorithms and source code have been released into the public
909 // domain. The authors of the FNV algorithmm look deliberate steps to disclose
910 // the algorhtm (sic) in a public forum soon after it was invented. More than
911 // a year passed after this public disclosure and the authors deliberately took
912 // no steps to patent the FNV algorithm. Therefore it is safe to say that the
913 // FNV authors have no patent claims on the FNV algorithm as published."
914
915 #define FNV_OFFSET_BASIS 2166136261u
916 #define FNV_PRIME32 16777619u
917
918 static uint32_t
xipHash32(const char * s)919 xipHash32(const char* s)
920 {
921 uint32_t hash;
922
923 hash = FNV_OFFSET_BASIS;
924 while (*s) {
925 hash ^= *s++;
926 hash *= FNV_PRIME32;
927 }
928 return hash;
929 }
930
931
932 // Normalize a TOC entry
933
934 // Normalize the TOC entry by converting relocatable pointers into 32-bit
935 // offsets from the beginning of the section containing the data. All
936 // addresses in the TOC are actually 32-bit offsets in the address space named
937 // in bits 16:31 of the link address of the image.
938
939 XIP_STATIC int
xipNormalizeToc(void * io_image,SbeXipToc * io_imageToc,SbeXipHashedToc ** io_fixedTocEntry,size_t * io_fixedEntriesRemaining)940 xipNormalizeToc(void* io_image, SbeXipToc *io_imageToc,
941 SbeXipHashedToc** io_fixedTocEntry,
942 size_t* io_fixedEntriesRemaining)
943 {
944 SbeXipToc hostToc;
945 int idSection, dataSection;
946 uint32_t idOffset, dataOffset;
947 char* hostString;
948 int rc;
949
950 do {
951
952 // Translate the TOC entry to host format. Then locate the
953 // sections/offsets of the Id string (which must be in .strings) and
954 // the data.
955
956 xipTranslateToc(&hostToc, io_imageToc);
957
958 hostString =
959 (char*)xipPore2Host(io_image,
960 xipFullAddress(io_image, hostToc.iv_id));
961
962 rc = xipPore2Section(io_image,
963 xipFullAddress(io_image, hostToc.iv_id),
964 &idSection,
965 &idOffset);
966 if (rc) break;
967
968 if (idSection != SBE_XIP_SECTION_STRINGS) {
969 rc = TRACE_ERROR(SBE_XIP_IMAGE_ERROR);
970 break;
971 }
972
973 rc = xipPore2Section(io_image,
974 xipFullAddress(io_image, hostToc.iv_data),
975 &dataSection,
976 &dataOffset);
977 if (rc) break;
978
979 // Now replace the Id and data pointers with their offsets, and update
980 // the data section in the TOC entry.
981
982 hostToc.iv_id = idOffset;
983 hostToc.iv_data = dataOffset;
984 hostToc.iv_section = dataSection;
985
986 // If this TOC entry is from .fixed, create a new record in .fixed_toc
987
988 if (hostToc.iv_section == SBE_XIP_SECTION_FIXED) {
989
990 if (*io_fixedEntriesRemaining == 0) {
991 rc = TRACE_ERRORX(SBE_XIP_TOC_ERROR,
992 "Too many TOC entries for .fixed\n");
993 break;
994 }
995 if (hostToc.iv_data != (uint16_t)hostToc.iv_data) {
996 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
997 "The .fixed section is too big to index\n");
998 break;
999 }
1000
1001 (*io_fixedTocEntry)->iv_hash = xipRevLe32(xipHash32(hostString));
1002 (*io_fixedTocEntry)->iv_offset = xipRevLe16(hostToc.iv_data);
1003 (*io_fixedTocEntry)->iv_type = hostToc.iv_type;
1004 (*io_fixedTocEntry)->iv_elements = hostToc.iv_elements;
1005
1006 (*io_fixedTocEntry)++;
1007 (*io_fixedEntriesRemaining)--;
1008 }
1009
1010 // Finally update the TOC entry
1011
1012 xipTranslateToc(io_imageToc, &hostToc);
1013
1014 } while (0);
1015
1016 return rc;
1017 }
1018
1019
1020 // Check for hash collisions in the .fixed mini-TOC. Note that endianness is
1021 // not an issue here, as we're comparing for equality.
1022
1023 XIP_STATIC int
xipHashCollision(SbeXipHashedToc * i_fixedToc,size_t i_entries)1024 xipHashCollision(SbeXipHashedToc* i_fixedToc, size_t i_entries)
1025 {
1026 int rc;
1027 size_t i, j;
1028
1029 rc = 0;
1030
1031 for (i = 0; i < i_entries; i++) {
1032 for (j = i + 1; j < i_entries; j++) {
1033 if (i_fixedToc[i].iv_hash == i_fixedToc[j].iv_hash) {
1034 rc = TRACE_ERRORX(SBE_XIP_HASH_COLLISION,
1035 "Hash collision at index %d\n",
1036 i);
1037 break;
1038 }
1039 }
1040 if (rc) break;
1041 }
1042
1043 return rc;
1044 }
1045
1046
1047 /// Decode a normalized image-format TOC entry into a host-format SbeXipItem
1048 /// structure
1049
1050 XIP_STATIC int
xipDecodeToc(void * i_image,SbeXipToc * i_imageToc,SbeXipItem * o_item)1051 xipDecodeToc(void* i_image,
1052 SbeXipToc* i_imageToc,
1053 SbeXipItem* o_item)
1054 {
1055 int rc;
1056 SbeXipToc hostToc;
1057 SbeXipSection dataSection, stringsSection;
1058
1059 do {
1060 if (!xipNormalized(i_image)) {
1061 rc = TRACE_ERROR(SBE_XIP_NOT_NORMALIZED);
1062 break;
1063 }
1064
1065
1066 // Translate the TOC entry and set the TOC pointer, data type and
1067 // number of elements in the outgoing structure. The Id string is
1068 // always located in the TOC_STRINGS section.
1069
1070 xipTranslateToc(&hostToc, i_imageToc);
1071
1072 o_item->iv_toc = i_imageToc;
1073 o_item->iv_type = hostToc.iv_type;
1074 o_item->iv_elements = hostToc.iv_elements;
1075
1076 rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_STRINGS,
1077 &stringsSection);
1078 if (rc) break;
1079
1080 o_item->iv_id =
1081 (char*)i_image + stringsSection.iv_offset + hostToc.iv_id;
1082
1083
1084 // The data (or text address) are addressed by relative offsets from
1085 // the beginning of their section. The TOC entry may remain in the TOC
1086 // even though the section has been removed from the image, so this
1087 // case needs to be covered.
1088
1089 rc = sbe_xip_get_section(i_image, hostToc.iv_section, &dataSection);
1090 if (rc) break;
1091
1092 if (dataSection.iv_size == 0) {
1093 rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT);
1094 break;
1095 }
1096
1097 o_item->iv_imageData =
1098 (void*)((uint8_t*)i_image +
1099 dataSection.iv_offset + hostToc.iv_data);
1100
1101 o_item->iv_address =
1102 xipLinkAddress(i_image) + dataSection.iv_offset + hostToc.iv_data;
1103
1104 o_item->iv_partial = 0;
1105
1106 } while (0);
1107 return rc;
1108 }
1109
1110
1111 /// Sort the TOC
1112
1113 XIP_STATIC int
xipSortToc(void * io_image)1114 xipSortToc(void* io_image)
1115 {
1116 int rc;
1117 SbeXipToc *hostToc;
1118 size_t entries;
1119 char* strings;
1120
1121 do {
1122 rc = xipQuickCheck(io_image, 1);
1123 if (rc) break;
1124
1125 if (xipSorted(io_image)) break;
1126
1127 rc = xipGetToc(io_image, &hostToc, &entries, 0, &strings);
1128 if (rc) break;
1129
1130 xipQuickSort(hostToc, 0, entries - 1, strings);
1131
1132 ((SbeXipHeader*)io_image)->iv_tocSorted = 1;
1133
1134 } while (0);
1135
1136 return rc;
1137 }
1138
1139
1140 // Pad the image with 0 to a given power-of-2 alignment. The image size is
1141 // modified to reflect the pad, but the caller must modify the section size to
1142 // reflect the pad.
1143
1144 XIP_STATIC int
xipPadImage(void * io_image,uint32_t i_allocation,uint32_t i_align,uint32_t * pad)1145 xipPadImage(void* io_image, uint32_t i_allocation,
1146 uint32_t i_align, uint32_t* pad)
1147 {
1148 int rc;
1149
1150 do {
1151 rc = 0;
1152
1153 if ((i_align == 0) || ((i_align & (i_align - 1)) != 0)) {
1154 rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT,
1155 "Alignment specification (%u) "
1156 "not a power-of-2\n",
1157 i_align);
1158 break;
1159 }
1160
1161 *pad = xipImageSize(io_image) % i_align;
1162 if (*pad != 0) {
1163 *pad = i_align - *pad;
1164
1165 if ((xipImageSize(io_image) + *pad) > i_allocation) {
1166 rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW);
1167 break;
1168 }
1169
1170 memset((void*)((unsigned long)io_image + xipImageSize(io_image)),
1171 0, *pad);
1172 xipSetImageSize(io_image, xipImageSize(io_image) + *pad);
1173 }
1174 } while (0);
1175
1176 return rc;
1177 }
1178
1179
1180 // Get the .fixed_toc section
1181
1182 XIP_STATIC int
xipGetFixedToc(void * io_image,SbeXipHashedToc ** o_imageToc,size_t * o_entries)1183 xipGetFixedToc(void* io_image,
1184 SbeXipHashedToc** o_imageToc,
1185 size_t* o_entries)
1186 {
1187 int rc;
1188 SbeXipSection section;
1189
1190 rc = sbe_xip_get_section(io_image, SBE_XIP_SECTION_FIXED_TOC, §ion);
1191 if (!rc) {
1192
1193 *o_imageToc =
1194 (SbeXipHashedToc*)((unsigned long)io_image + section.iv_offset);
1195
1196 *o_entries = section.iv_size / sizeof(SbeXipHashedToc);
1197 }
1198
1199 return rc;
1200 }
1201
1202
1203 // Search for an item in the fixed TOC, and populate a partial TOC entry if
1204 // requested. This table is small and unsorted so a linear search is
1205 // adequate. The TOC structures are also small so all byte-reversal is done
1206 // 'by hand' rather than with a translate-type API.
1207
1208 XIP_STATIC int
xipFixedFind(void * i_image,const char * i_id,SbeXipItem * o_item)1209 xipFixedFind(void* i_image, const char* i_id, SbeXipItem* o_item)
1210 {
1211 int rc;
1212 SbeXipHashedToc* toc;
1213 size_t entries;
1214 uint32_t hash;
1215 SbeXipSection fixedSection;
1216 uint32_t offset;
1217
1218 do {
1219 rc = xipGetFixedToc(i_image, &toc, &entries);
1220 if (rc) break;
1221
1222 for (hash = xipRevLe32(xipHash32(i_id)); entries != 0; entries--, toc++) {
1223 if (toc->iv_hash == hash) break;
1224 }
1225
1226 if (entries == 0) {
1227 rc = SBE_XIP_ITEM_NOT_FOUND;
1228 break;
1229 } else {
1230 rc = 0;
1231 }
1232
1233 // The caller may have requested a lookup only (o_item == 0), in which
1234 // case we're done. Otherwise we create a partial SbeXipItem and
1235 // populate the non-0 fields analogously to the xipDecodeToc()
1236 // routine. The data resides in the .fixed section in this case.
1237
1238 if (o_item == 0) break;
1239
1240 o_item->iv_partial = 1;
1241 o_item->iv_toc = 0;
1242 o_item->iv_id = 0;
1243
1244 o_item->iv_type = toc->iv_type;
1245 o_item->iv_elements = toc->iv_elements;
1246
1247 rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_FIXED, &fixedSection);
1248 if (rc) break;
1249
1250 if (fixedSection.iv_size == 0) {
1251 rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT);
1252 break;
1253 }
1254
1255 offset = fixedSection.iv_offset + xipRevLe16(toc->iv_offset);
1256
1257 o_item->iv_imageData = (void*)((uint8_t*)i_image + offset);
1258 o_item->iv_address = xipLinkAddress(i_image) + offset;
1259
1260 } while (0);
1261
1262 return rc;
1263 }
1264
1265
1266 // Search for an item in the special built-in TOC of header fields, and
1267 // populate a partial TOC entry if requested.
1268 //
1269 // This facility was added to allow header data to be searched by name even
1270 // when the TOC has been stripped. This API will only be used in the case of a
1271 // stripped TOC since the header fields are also indexed in the main TOC.
1272 //
1273 // The table is allocated on the stack in order to make this code concurrently
1274 // patchable in PHYP (although PHYP applications will never use this code).
1275 // The table is small and unsorted so a linear search is adequate, and the
1276 // stack requirememts are small.
1277
1278 XIP_STATIC int
xipHeaderFind(void * i_image,const char * i_id,SbeXipItem * o_item)1279 xipHeaderFind(void* i_image, const char* i_id, SbeXipItem* o_item)
1280 {
1281 int rc;
1282 unsigned i;
1283 uint32_t offset;
1284 SbeXipSection headerSection;
1285
1286 #define HEADER_TOC(id, field, type) \
1287 {#id, offsetof(SbeXipHeader, field), type}
1288
1289 struct HeaderToc {
1290
1291 const char* iv_id;
1292 uint16_t iv_offset;
1293 uint8_t iv_type;
1294
1295 } toc[] = {
1296
1297 HEADER_TOC(magic, iv_magic, SBE_XIP_UINT64),
1298 HEADER_TOC(entry_offset, iv_entryOffset, SBE_XIP_UINT64),
1299 HEADER_TOC(link_address, iv_linkAddress, SBE_XIP_UINT64),
1300
1301 HEADER_TOC(image_size, iv_imageSize, SBE_XIP_UINT32),
1302 HEADER_TOC(build_date, iv_buildDate, SBE_XIP_UINT32),
1303 HEADER_TOC(build_time, iv_buildTime, SBE_XIP_UINT32),
1304
1305 HEADER_TOC(header_version, iv_headerVersion, SBE_XIP_UINT8),
1306 HEADER_TOC(toc_normalized, iv_normalized, SBE_XIP_UINT8),
1307 HEADER_TOC(toc_sorted, iv_tocSorted, SBE_XIP_UINT8),
1308
1309 HEADER_TOC(build_user, iv_buildUser, SBE_XIP_STRING),
1310 HEADER_TOC(build_host, iv_buildHost, SBE_XIP_STRING),
1311
1312 };
1313
1314 do {
1315
1316 rc = SBE_XIP_ITEM_NOT_FOUND;
1317 for (i = 0; i < (sizeof(toc) / sizeof(struct HeaderToc)); i++) {
1318 if (strcmp(i_id, toc[i].iv_id) == 0) {
1319 rc = 0;
1320 break;
1321 }
1322 }
1323
1324 if (rc) break;
1325
1326 // The caller may have requested a lookup only (o_item == 0), in which
1327 // case we're done. Otherwise we create a partial SbeXipItem and
1328 // populate the non-0 fields analogously to the xipDecodeToc()
1329 // routine. The data resides in the .fixed section in this case.
1330
1331 if (o_item == 0) break;
1332
1333 o_item->iv_partial = 1;
1334 o_item->iv_toc = 0;
1335 o_item->iv_id = 0;
1336
1337 o_item->iv_type = toc[i].iv_type;
1338 o_item->iv_elements = 1; /* True for now... */
1339
1340 rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_HEADER,
1341 &headerSection);
1342 if (rc) break;
1343
1344 if (headerSection.iv_size == 0) {
1345 rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT);
1346 break;
1347 }
1348
1349 offset = headerSection.iv_offset + toc[i].iv_offset;
1350
1351 o_item->iv_imageData = (void*)((uint8_t*)i_image + offset);
1352 o_item->iv_address = xipLinkAddress(i_image) + offset;
1353
1354 } while (0);
1355
1356 return rc;
1357 }
1358
1359
1360 ////////////////////////////////////////////////////////////////////////////
1361 // Published API
1362 ////////////////////////////////////////////////////////////////////////////
1363
1364 int
sbe_xip_validate(void * i_image,const uint32_t i_size)1365 sbe_xip_validate(void* i_image, const uint32_t i_size)
1366 {
1367 SbeXipHeader hostHeader;
1368 int rc = 0, i;
1369 uint32_t linkAddress, imageSize, extent, offset, size;
1370 uint8_t alignment;
1371
1372 sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image);
1373
1374 do {
1375
1376 // Validate C/Assembler constraints.
1377
1378 if (sizeof(SbeXipSection) != SIZE_OF_SBE_XIP_SECTION) {
1379 rc = TRACE_ERRORX(SBE_XIP_BUG,
1380 "C/Assembler size mismatch(%d/%d) "
1381 "for SbeXipSection\n",
1382 sizeof(SbeXipSection), SIZE_OF_SBE_XIP_SECTION);
1383 break;
1384 }
1385
1386 if (sizeof(SbeXipToc) != SIZE_OF_SBE_XIP_TOC) {
1387 rc = TRACE_ERRORX(SBE_XIP_BUG,
1388 "C/Assembler size mismatch(%d/%d) "
1389 "for SbeXipToc\n",
1390 sizeof(SbeXipToc), SIZE_OF_SBE_XIP_TOC);
1391 break;
1392 }
1393
1394 if (sizeof(SbeXipHashedToc) != SIZE_OF_SBE_XIP_HASHED_TOC) {
1395 rc = TRACE_ERRORX(SBE_XIP_BUG,
1396 "C/Assembler size mismatch(%d/%d) "
1397 "for SbeXipHashedToc\n",
1398 sizeof(SbeXipHashedToc),
1399 SIZE_OF_SBE_XIP_HASHED_TOC);
1400 break;
1401 }
1402
1403 // Validate the image pointer and magic number
1404
1405 rc = xipQuickCheck(i_image, 0);
1406 if (rc) break;
1407
1408 // Validate the image size
1409
1410 linkAddress = hostHeader.iv_linkAddress;
1411 imageSize = hostHeader.iv_imageSize;
1412 extent = linkAddress + imageSize;
1413
1414 if (imageSize < sizeof(SbeXipHeader)) {
1415 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1416 "sbe_xip_validate(%p, %u) : "
1417 "The image size recorded in the image "
1418 "(%u) is smaller than the header size.\n",
1419 i_image, i_size, imageSize);
1420 break;
1421 }
1422 if (imageSize != i_size) {
1423 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1424 "sbe_xip_validate(%p, %u) : "
1425 "The image size recorded in the image "
1426 "(%u) does not match the i_size parameter.\n",
1427 i_image, i_size, imageSize);
1428 break;
1429 }
1430 if (extent <= linkAddress) {
1431 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1432 "sbe_xip_validate(%p, %u) : "
1433 "Given the link address (%u) and the "
1434 "image size, the image wraps the address space\n",
1435 i_image, i_size, linkAddress);
1436 break;
1437 }
1438 if ((imageSize % SBE_XIP_FINAL_ALIGNMENT) != 0) {
1439 rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
1440 "sbe_xip_validate(%p, %u) : "
1441 "The image size (%u) is not a multiple of %u\n",
1442 i_image, i_size, imageSize,
1443 SBE_XIP_FINAL_ALIGNMENT);
1444 break;
1445 }
1446
1447 // Validate that all sections appear to be within the image
1448 // bounds, and are aligned correctly.
1449
1450 for (i = 0; i < SBE_XIP_SECTIONS; i++) {
1451
1452 offset = hostHeader.iv_section[i].iv_offset;
1453 size = hostHeader.iv_section[i].iv_size;
1454 alignment = hostHeader.iv_section[i].iv_alignment;
1455
1456 if ((offset > imageSize) ||
1457 ((offset + size) > imageSize) ||
1458 ((offset + size) < offset)) {
1459 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1460 "Section %d does not appear to be within "
1461 "the bounds of the image\n"
1462 "offset = %u, size = %u, image size = %u\n",
1463 i, offset, size, imageSize);
1464 break;
1465 }
1466 if ((offset % alignment) != 0) {
1467 rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
1468 "Section %d requires %d-byte initial "
1469 "alignment but the section offset is %u\n",
1470 i, alignment, offset);
1471 break;
1472 }
1473 }
1474 if (rc) break;
1475
1476 // If the TOC exists and the image is normalized, validate each TOC
1477 // entry.
1478
1479 size = hostHeader.iv_section[SBE_XIP_SECTION_TOC].iv_size;
1480 if (size != 0) {
1481 if (xipNormalized(i_image)) {
1482 rc = sbe_xip_map_toc(i_image, xipValidateTocEntry, 0);
1483 if (rc) break;
1484 }
1485 }
1486 } while (0);
1487 return rc;
1488 }
1489
1490
1491 int
sbe_xip_validate2(void * i_image,const uint32_t i_size,const uint32_t i_maskIgnores)1492 sbe_xip_validate2(void* i_image, const uint32_t i_size, const uint32_t i_maskIgnores)
1493 {
1494 SbeXipHeader hostHeader;
1495 int rc = 0, i;
1496 uint32_t linkAddress, imageSize, extent, offset, size;
1497 uint8_t alignment;
1498
1499 sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image);
1500
1501 do {
1502
1503 // Validate C/Assembler constraints.
1504
1505 if (sizeof(SbeXipSection) != SIZE_OF_SBE_XIP_SECTION) {
1506 rc = TRACE_ERRORX(SBE_XIP_BUG,
1507 "C/Assembler size mismatch(%d/%d) "
1508 "for SbeXipSection\n",
1509 sizeof(SbeXipSection), SIZE_OF_SBE_XIP_SECTION);
1510 break;
1511 }
1512
1513 if (sizeof(SbeXipToc) != SIZE_OF_SBE_XIP_TOC) {
1514 rc = TRACE_ERRORX(SBE_XIP_BUG,
1515 "C/Assembler size mismatch(%d/%d) "
1516 "for SbeXipToc\n",
1517 sizeof(SbeXipToc), SIZE_OF_SBE_XIP_TOC);
1518 break;
1519 }
1520
1521 if (sizeof(SbeXipHashedToc) != SIZE_OF_SBE_XIP_HASHED_TOC) {
1522 rc = TRACE_ERRORX(SBE_XIP_BUG,
1523 "C/Assembler size mismatch(%d/%d) "
1524 "for SbeXipHashedToc\n",
1525 sizeof(SbeXipHashedToc),
1526 SIZE_OF_SBE_XIP_HASHED_TOC);
1527 break;
1528 }
1529
1530 // Validate the image pointer and magic number
1531
1532 rc = xipQuickCheck(i_image, 0);
1533 if (rc) break;
1534
1535 // Validate the image size
1536
1537 linkAddress = hostHeader.iv_linkAddress;
1538 imageSize = hostHeader.iv_imageSize;
1539 extent = linkAddress + imageSize;
1540
1541 if (imageSize < sizeof(SbeXipHeader)) {
1542 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1543 "sbe_xip_validate2(%p, %u) : "
1544 "The image size recorded in the image "
1545 "(%u) is smaller than the header size.\n",
1546 i_image, i_size, imageSize);
1547 break;
1548 }
1549 if (imageSize != i_size && !(i_maskIgnores & SBE_XIP_IGNORE_FILE_SIZE)) {
1550 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1551 "sbe_xip_validate2(%p, %u) : "
1552 "The image size recorded in the image "
1553 "(%u) does not match the i_size parameter.\n",
1554 i_image, i_size, imageSize);
1555 break;
1556 }
1557 if (extent <= linkAddress) {
1558 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1559 "sbe_xip_validate2(%p, %u) : "
1560 "Given the link address (%u) and the "
1561 "image size, the image wraps the address space\n",
1562 i_image, i_size, linkAddress);
1563 break;
1564 }
1565 if ((imageSize % SBE_XIP_FINAL_ALIGNMENT) != 0) {
1566 rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
1567 "sbe_xip_validate2(%p, %u) : "
1568 "The image size (%u) is not a multiple of %u\n",
1569 i_image, i_size, imageSize,
1570 SBE_XIP_FINAL_ALIGNMENT);
1571 break;
1572 }
1573
1574 // Validate that all sections appear to be within the image
1575 // bounds, and are aligned correctly.
1576
1577 for (i = 0; i < SBE_XIP_SECTIONS; i++) {
1578
1579 offset = hostHeader.iv_section[i].iv_offset;
1580 size = hostHeader.iv_section[i].iv_size;
1581 alignment = hostHeader.iv_section[i].iv_alignment;
1582
1583 if ((offset > imageSize) ||
1584 ((offset + size) > imageSize) ||
1585 ((offset + size) < offset)) {
1586 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1587 "Section %d does not appear to be within "
1588 "the bounds of the image\n"
1589 "offset = %u, size = %u, image size = %u\n",
1590 i, offset, size, imageSize);
1591 break;
1592 }
1593 if ((offset % alignment) != 0) {
1594 rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
1595 "Section %d requires %d-byte initial "
1596 "alignment but the section offset is %u\n",
1597 i, alignment, offset);
1598 break;
1599 }
1600 }
1601 if (rc) break;
1602
1603 // If the TOC exists and the image is normalized, validate each TOC
1604 // entry.
1605
1606 size = hostHeader.iv_section[SBE_XIP_SECTION_TOC].iv_size;
1607 if (size != 0) {
1608 if (xipNormalized(i_image)) {
1609 rc = sbe_xip_map_toc(i_image, xipValidateTocEntry, 0);
1610 if (rc) break;
1611 }
1612 }
1613 } while (0);
1614 return rc;
1615 }
1616
1617
1618 // Normalization:
1619 //
1620 // 1. Normalize the TOC, unless the image is already normalized. The image
1621 // must be marked as normalized before sorting.
1622 //
1623 // 2. Sort the TOC.
1624 //
1625 // 3. Clear the section offsets of any empty sections to make the section
1626 // table reports less confusing.
1627 //
1628 // 4. Clear normalization status on any failure.
1629
1630 int
sbe_xip_normalize(void * io_image)1631 sbe_xip_normalize(void* io_image)
1632 {
1633 int rc, i;
1634 SbeXipSection section;
1635 SbeXipToc* imageToc;
1636 SbeXipHashedToc* fixedImageToc = NULL;
1637 SbeXipHashedToc* fixedTocEntry = NULL;
1638 size_t tocEntries = 0;
1639 size_t fixedTocEntries = 0;
1640 size_t fixedEntriesRemaining = 0;
1641
1642 do {
1643 rc = xipQuickCheck(io_image, 0);
1644 if (rc) break;
1645
1646 if (!xipNormalized(io_image)) {
1647
1648 rc = xipGetToc(io_image, &imageToc, &tocEntries, 0, 0);
1649 if (rc) break;
1650
1651 rc = xipGetFixedToc(io_image, &fixedImageToc, &fixedTocEntries);
1652 if (rc) break;
1653
1654 fixedTocEntry = fixedImageToc;
1655 fixedEntriesRemaining = fixedTocEntries;
1656
1657 for (; tocEntries--; imageToc++) {
1658 rc = xipNormalizeToc(io_image, imageToc,
1659 &fixedTocEntry, &fixedEntriesRemaining);
1660 if (rc) break;
1661
1662 }
1663 if (rc) break;
1664
1665 if (fixedEntriesRemaining != 0) {
1666 rc = TRACE_ERRORX(SBE_XIP_TOC_ERROR,
1667 "Not enough TOC entries for .fixed");
1668 break;
1669 }
1670
1671 rc = xipHashCollision(fixedImageToc, fixedTocEntries);
1672 if (rc) break;
1673
1674 ((SbeXipHeader*)io_image)->iv_normalized = 1;
1675 }
1676
1677 rc = xipSortToc(io_image);
1678 if (rc) break;
1679
1680 for (i = 0; i < SBE_XIP_SECTIONS; i++) {
1681 rc = sbe_xip_get_section(io_image, i, §ion);
1682 if (rc) break;
1683 if (section.iv_size == 0) {
1684 xipSetSectionOffset(io_image, i, 0);
1685 }
1686 }
1687 if (rc) break;
1688
1689 } while(0);
1690
1691 ((SbeXipHeader*)io_image)->iv_normalized = (rc == 0);
1692
1693 return rc;
1694 }
1695
1696
1697 int
sbe_xip_image_size(void * io_image,uint32_t * o_size)1698 sbe_xip_image_size(void* io_image, uint32_t* o_size)
1699 {
1700 int rc;
1701
1702 rc = xipQuickCheck(io_image, 0);
1703 if (!rc) {
1704 *o_size = xipImageSize(io_image);
1705 }
1706 return rc;
1707 }
1708
1709
1710 int
sbe_xip_get_section(const void * i_image,const int i_sectionId,SbeXipSection * o_hostSection)1711 sbe_xip_get_section(const void* i_image,
1712 const int i_sectionId,
1713 SbeXipSection* o_hostSection)
1714 {
1715 int rc;
1716 SbeXipSection *imageSection = NULL;
1717
1718 rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection);
1719
1720 if (!rc) {
1721 xipTranslateSection(o_hostSection, imageSection);
1722 }
1723
1724 return rc;
1725 }
1726
1727
1728 // If the 'big' TOC is not present, search the mini-TOCs that only index the
1729 // .fixed and .header sections.
1730
1731 int
sbe_xip_find(void * i_image,const char * i_id,SbeXipItem * o_item)1732 sbe_xip_find(void* i_image,
1733 const char* i_id,
1734 SbeXipItem* o_item)
1735 {
1736 int rc;
1737 SbeXipToc* toc;
1738 SbeXipItem item, *pitem;
1739 SbeXipSection* tocSection;
1740
1741 do {
1742 rc = xipQuickCheck(i_image, 1);
1743 if (rc) break;
1744
1745 rc = xipGetSectionPointer(i_image, SBE_XIP_SECTION_TOC, &tocSection);
1746 if (rc) break;
1747
1748 if (tocSection->iv_size == 0) {
1749 rc = xipFixedFind(i_image, i_id, o_item);
1750 if (rc) {
1751 rc = xipHeaderFind(i_image, i_id, o_item);
1752 }
1753 break;
1754 }
1755
1756 if (xipSorted(i_image)) {
1757 rc = xipBinarySearch(i_image, i_id, &toc);
1758 } else {
1759 rc = xipLinearSearch(i_image, i_id, &toc);
1760 }
1761 if (rc) break;
1762
1763 if (o_item) {
1764 pitem = o_item;
1765 } else {
1766 pitem = &item;
1767 }
1768 rc = xipDecodeToc(i_image, toc, pitem);
1769 if (rc) break;
1770
1771 } while (0);
1772
1773 return rc;
1774 }
1775
1776
1777 int
sbe_xip_map_halt(void * io_image,int (* i_fn)(void * io_image,const uint64_t i_poreAddress,const char * i_rcString,void * io_arg),void * io_arg)1778 sbe_xip_map_halt(void* io_image,
1779 int (*i_fn)(void* io_image,
1780 const uint64_t i_poreAddress,
1781 const char* i_rcString,
1782 void* io_arg),
1783 void* io_arg)
1784 {
1785 int rc;
1786 SbeXipSection haltSection;
1787 SbeXipHalt *halt;
1788 uint32_t size;
1789 uint32_t actualSize;
1790
1791 do {
1792 rc = xipQuickCheck(io_image, 0);
1793 if (rc) break;
1794
1795 rc = sbe_xip_get_section(io_image, SBE_XIP_SECTION_HALT, &haltSection);
1796 if (rc) break;
1797
1798 halt = (SbeXipHalt*)((unsigned long)io_image + haltSection.iv_offset);
1799 size = haltSection.iv_size;
1800
1801 while (size) {
1802
1803 rc = i_fn(io_image,
1804 xipRevLe64(halt->iv_address),
1805 halt->iv_string,
1806 io_arg);
1807 if (rc) break;
1808
1809 // The SbeXipHalt structure claims a 4-character string. The
1810 // computation below computes the actual record size based on the
1811 // actual length of the string, including the 0-byte termination.
1812
1813 actualSize = 8 + (((strlen(halt->iv_string) + 4) / 4) * 4);
1814
1815 if (size < actualSize) {
1816 rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
1817 "The .halt section is improperly formed\n");
1818 break;
1819 }
1820
1821 size -= actualSize;
1822 halt = (SbeXipHalt*)((unsigned long)halt + actualSize);
1823 };
1824
1825 if (rc) break;
1826
1827 } while (0);
1828
1829 return rc;
1830 }
1831
1832
1833 typedef struct {
1834 uint64_t iv_address;
1835 const char* iv_string;
1836 } GetHaltStruct;
1837
1838
1839 XIP_STATIC int
xipGetHaltMap(void * io_image,const uint64_t i_poreAddress,const char * i_rcString,void * io_arg)1840 xipGetHaltMap(void* io_image,
1841 const uint64_t i_poreAddress,
1842 const char* i_rcString,
1843 void* io_arg)
1844 {
1845 int rc;
1846
1847 GetHaltStruct* s = (GetHaltStruct*)io_arg;
1848
1849 (void)io_image;
1850
1851 if (i_poreAddress == s->iv_address) {
1852 s->iv_string = i_rcString;
1853 rc = -1;
1854 } else {
1855 rc = 0;
1856 }
1857
1858 return rc;
1859 }
1860
1861
1862 int
sbe_xip_get_halt(void * io_image,const uint64_t i_poreAddress,const char ** o_rcString)1863 sbe_xip_get_halt(void* io_image,
1864 const uint64_t i_poreAddress,
1865 const char** o_rcString)
1866 {
1867 int rc;
1868 GetHaltStruct s;
1869
1870 s.iv_address = i_poreAddress;
1871 do {
1872 rc = xipQuickCheck(io_image, 0);
1873 if (rc) break;
1874
1875 rc = sbe_xip_map_halt(io_image, xipGetHaltMap, &s);
1876 if (rc == 0) {
1877 rc = TRACE_ERRORX(SBE_XIP_ITEM_NOT_FOUND,
1878 "sbe_xip_get_halt: No HALT code is associated "
1879 "with address " F0x012llx "\n", i_poreAddress);
1880 } else if (rc < 0) {
1881 *o_rcString = s.iv_string;
1882 rc = 0;
1883 }
1884 } while (0);
1885
1886 return rc;
1887 }
1888
1889
1890 int
sbe_xip_get_scalar(void * i_image,const char * i_id,uint64_t * o_data)1891 sbe_xip_get_scalar(void *i_image, const char* i_id, uint64_t* o_data)
1892 {
1893 int rc;
1894 SbeXipItem item;
1895
1896 rc = sbe_xip_find(i_image, i_id, &item);
1897 if (!rc) {
1898 switch (item.iv_type) {
1899 case SBE_XIP_UINT8:
1900 *o_data = *((uint8_t*)(item.iv_imageData));
1901 break;
1902 case SBE_XIP_UINT32:
1903 *o_data = xipRevLe32(*((uint32_t*)(item.iv_imageData)));
1904 break;
1905 case SBE_XIP_UINT64:
1906 *o_data = xipRevLe64(*((uint64_t*)(item.iv_imageData)));
1907 break;
1908 case SBE_XIP_ADDRESS:
1909 *o_data = item.iv_address;
1910 break;
1911 default:
1912 rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
1913 break;
1914 }
1915 }
1916 return rc;
1917 }
1918
1919
1920 int
sbe_xip_get_element(void * i_image,const char * i_id,const uint32_t i_index,uint64_t * o_data)1921 sbe_xip_get_element(void *i_image,
1922 const char* i_id,
1923 const uint32_t i_index,
1924 uint64_t* o_data)
1925 {
1926 int rc;
1927 SbeXipItem item;
1928
1929 do {
1930 rc = sbe_xip_find(i_image, i_id, &item);
1931 if (rc) break;
1932
1933 if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) {
1934 rc = TRACE_ERROR(SBE_XIP_BOUNDS_ERROR);
1935 break;
1936 }
1937
1938 switch (item.iv_type) {
1939 case SBE_XIP_UINT8:
1940 *o_data = ((uint8_t*)(item.iv_imageData))[i_index];
1941 break;
1942 case SBE_XIP_UINT32:
1943 *o_data = xipRevLe32(((uint32_t*)(item.iv_imageData))[i_index]);
1944 break;
1945 case SBE_XIP_UINT64:
1946 *o_data = xipRevLe64(((uint64_t*)(item.iv_imageData))[i_index]);
1947 break;
1948 default:
1949 rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
1950 break;
1951 }
1952 if (rc) break;
1953
1954 } while (0);
1955 return rc;
1956 }
1957
1958
1959 int
sbe_xip_get_string(void * i_image,const char * i_id,char ** o_data)1960 sbe_xip_get_string(void *i_image, const char* i_id, char** o_data)
1961 {
1962 int rc;
1963 SbeXipItem item;
1964
1965 rc = sbe_xip_find(i_image, i_id, &item);
1966 if (!rc) {
1967 switch (item.iv_type) {
1968 case SBE_XIP_STRING:
1969 *o_data = (char*)(item.iv_imageData);
1970 break;
1971 default:
1972 rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
1973 break;
1974 }
1975 }
1976 return rc;
1977 }
1978
1979
1980 int
sbe_xip_read_uint64(const void * i_image,const uint64_t i_poreAddress,uint64_t * o_data)1981 sbe_xip_read_uint64(const void *i_image,
1982 const uint64_t i_poreAddress,
1983 uint64_t* o_data)
1984 {
1985 int rc;
1986
1987 do {
1988 rc = xipQuickCheck(i_image, 0);
1989 if (rc) break;
1990
1991 rc = xipValidatePoreAddress(i_image, i_poreAddress, 8);
1992 if (rc) break;
1993
1994 if (i_poreAddress % 8) {
1995 rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
1996 break;
1997 }
1998
1999 *o_data =
2000 xipRevLe64(*((uint64_t*)xipPore2Host(i_image, i_poreAddress)));
2001
2002 } while(0);
2003
2004 return rc;
2005 }
2006
2007
2008 int
sbe_xip_set_scalar(void * io_image,const char * i_id,const uint64_t i_data)2009 sbe_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data)
2010 {
2011 int rc;
2012 SbeXipItem item;
2013
2014 rc = sbe_xip_find(io_image, i_id, &item);
2015 if (!rc) {
2016 switch(item.iv_type) {
2017 case SBE_XIP_UINT8:
2018 *((uint8_t*)(item.iv_imageData)) = (uint8_t)i_data;
2019 break;
2020 case SBE_XIP_UINT32:
2021 *((uint32_t*)(item.iv_imageData)) = xipRevLe32((uint32_t)i_data);
2022 break;
2023 case SBE_XIP_UINT64:
2024 *((uint64_t*)(item.iv_imageData)) = xipRevLe64((uint64_t)i_data);
2025 break;
2026 default:
2027 rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
2028 break;
2029 }
2030 }
2031 return rc;
2032 }
2033
2034
2035 int
sbe_xip_set_element(void * i_image,const char * i_id,const uint32_t i_index,const uint64_t i_data)2036 sbe_xip_set_element(void *i_image,
2037 const char* i_id,
2038 const uint32_t i_index,
2039 const uint64_t i_data)
2040 {
2041 int rc;
2042 SbeXipItem item;
2043
2044 do {
2045 rc = sbe_xip_find(i_image, i_id, &item);
2046 if (rc) break;
2047
2048 if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) {
2049 rc = TRACE_ERROR(SBE_XIP_BOUNDS_ERROR);
2050 break;
2051 }
2052
2053 switch (item.iv_type) {
2054 case SBE_XIP_UINT8:
2055 ((uint8_t*)(item.iv_imageData))[i_index] = (uint8_t)i_data;
2056 break;
2057 case SBE_XIP_UINT32:
2058 ((uint32_t*)(item.iv_imageData))[i_index] =
2059 xipRevLe32((uint32_t)i_data);
2060 break;
2061 case SBE_XIP_UINT64:
2062 ((uint64_t*)(item.iv_imageData))[i_index] =
2063 xipRevLe64((uint64_t)i_data);
2064 break;
2065 default:
2066 rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
2067 break;
2068 }
2069 if (rc) break;
2070
2071 } while (0);
2072
2073 return rc;
2074 }
2075
2076
2077 int
sbe_xip_set_string(void * i_image,const char * i_id,const char * i_data)2078 sbe_xip_set_string(void *i_image, const char* i_id, const char* i_data)
2079 {
2080 int rc;
2081 SbeXipItem item;
2082 char* dest;
2083
2084 rc = sbe_xip_find(i_image, i_id, &item);
2085 if (!rc) {
2086 switch (item.iv_type) {
2087 case SBE_XIP_STRING:
2088 dest = (char*)(item.iv_imageData);
2089 if (strlen(dest) < strlen(i_data)) {
2090 memcpy(dest, i_data, strlen(dest));
2091 } else {
2092 strcpy(dest, i_data);
2093 }
2094 break;
2095 default:
2096 rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
2097 break;
2098 }
2099 }
2100 return rc;
2101 }
2102
2103
2104 int
sbe_xip_write_uint64(void * io_image,const uint64_t i_poreAddress,const uint64_t i_data)2105 sbe_xip_write_uint64(void *io_image,
2106 const uint64_t i_poreAddress,
2107 const uint64_t i_data)
2108 {
2109 int rc;
2110
2111 do {
2112 rc = xipQuickCheck(io_image, 0);
2113 if (rc) break;
2114
2115 rc = xipValidatePoreAddress(io_image, i_poreAddress, 8);
2116 if (rc) break;
2117
2118 if (i_poreAddress % 8) {
2119 rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
2120 break;
2121 }
2122
2123 *((uint64_t*)xipPore2Host(io_image, i_poreAddress)) =
2124 xipRevLe64(i_data);
2125
2126 } while(0);
2127
2128 return rc;
2129 }
2130
2131
2132 int
sbe_xip_delete_section(void * io_image,const int i_sectionId)2133 sbe_xip_delete_section(void* io_image, const int i_sectionId)
2134 {
2135 int rc, final;
2136 SbeXipSection section;
2137
2138 do {
2139 rc = xipQuickCheck(io_image, 1);
2140 if (rc) break;
2141
2142 rc = sbe_xip_get_section(io_image, i_sectionId, §ion);
2143 if (rc) break;
2144
2145
2146 // Deleting an empty section is a NOP. Otherwise the section must be
2147 // the final section of the image. Update the sizes and re-establish
2148 // the final image alignment.
2149
2150 if (section.iv_size == 0) break;
2151
2152 rc = xipFinalSection(io_image, &final);
2153 if (rc) break;
2154
2155 if (final != i_sectionId) {
2156 rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR,
2157 "Attempt to delete non-final section %d\n",
2158 i_sectionId);
2159 break;
2160 }
2161
2162 xipSetSectionOffset(io_image, i_sectionId, 0);
2163 xipSetSectionSize(io_image, i_sectionId, 0);
2164
2165
2166 // For cleanliness we also remove any alignment padding that had been
2167 // appended between the now-last section and the deleted section, then
2168 // re-establish the final alignment. The assumption is that all images
2169 // always have the correct final alignment, so there is no way this
2170 // could overflow a designated buffer space since the image size is
2171 // the same or has been reduced.
2172
2173 rc = xipFinalSection(io_image, &final);
2174 if (rc) break;
2175
2176 rc = sbe_xip_get_section(io_image, final, §ion);
2177 if (rc) break;
2178
2179 xipSetImageSize(io_image, section.iv_offset + section.iv_size);
2180 xipFinalAlignment(io_image);
2181
2182 } while (0);
2183
2184 return rc;
2185 }
2186
2187
2188 #ifndef PPC_HYP
2189
2190 // This API is not needed by PHYP procedures, and is elided since PHYP does
2191 // not support malloc().
2192
2193 int
sbe_xip_duplicate_section(const void * i_image,const int i_sectionId,void ** o_duplicate,uint32_t * o_size)2194 sbe_xip_duplicate_section(const void* i_image,
2195 const int i_sectionId,
2196 void** o_duplicate,
2197 uint32_t* o_size)
2198 {
2199 SbeXipSection section;
2200 int rc;
2201
2202 *o_duplicate = 0;
2203
2204 do {
2205 rc = xipQuickCheck(i_image, 0);
2206 if (rc) break;
2207
2208 rc = sbe_xip_get_section(i_image, i_sectionId, §ion);
2209 if (rc) break;
2210
2211 if (section.iv_size == 0) {
2212 rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR,
2213 "Attempt to duplicate empty section %d\n",
2214 i_sectionId);
2215 break;
2216 }
2217
2218 *o_duplicate = malloc(section.iv_size);
2219 *o_size = section.iv_size;
2220
2221 if (*o_duplicate == 0) {
2222 rc = TRACE_ERROR(SBE_XIP_NO_MEMORY);
2223 break;
2224 }
2225
2226 memcpy(*o_duplicate,
2227 xipHostAddressFromOffset(i_image, section.iv_offset),
2228 section.iv_size);
2229
2230
2231 } while (0);
2232
2233 if (rc) {
2234 free(*o_duplicate);
2235 *o_duplicate = 0;
2236 *o_size = 0;
2237 }
2238
2239 return rc;
2240 }
2241
2242 #endif // PPC_HYP
2243
2244
2245 // The append must be done in such a way that if the append fails, the image
2246 // is not modified. This behavior is required by applications that
2247 // speculatively append until the allocation fails, but still require the
2248 // final image to be valid. To accomplish this the initial image size and
2249 // section statistics are captured at entry, and restored in the event of an
2250 // error.
2251
2252 int
sbe_xip_append(void * io_image,const int i_sectionId,const void * i_data,const uint32_t i_size,const uint32_t i_allocation,uint32_t * o_sectionOffset)2253 sbe_xip_append(void* io_image,
2254 const int i_sectionId,
2255 const void* i_data,
2256 const uint32_t i_size,
2257 const uint32_t i_allocation,
2258 uint32_t* o_sectionOffset)
2259 {
2260 SbeXipSection section, initialSection;
2261 int rc, final, restoreOnError;
2262 void* hostAddress;
2263 uint32_t pad;
2264 uint32_t initialSize = 0;
2265
2266 do {
2267 restoreOnError = 0;
2268
2269 rc = xipQuickCheck(io_image, 1);
2270 if (rc) break;
2271
2272 rc = sbe_xip_get_section(io_image, i_sectionId, §ion);
2273 if (rc) break;
2274
2275 if (i_size == 0) break;
2276
2277 initialSection = section;
2278 initialSize = xipImageSize(io_image);
2279 restoreOnError = 1;
2280
2281 if (section.iv_size == 0) {
2282
2283 // The section is empty, and now becomes the final section. Pad
2284 // the image to the specified section alignment. Note that the
2285 // size of the previously final section does not change.
2286
2287 rc = xipPadImage(io_image, i_allocation, section.iv_alignment,
2288 &pad);
2289 if (rc) break;
2290 section.iv_offset = xipImageSize(io_image);
2291
2292 } else {
2293
2294 // Otherwise, the section must be the final section in order to
2295 // continue. Remove any padding from the image.
2296
2297 rc = xipFinalSection(io_image, &final);
2298 if (rc) break;
2299
2300 if (final != i_sectionId) {
2301 rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR,
2302 "Attempt to append to non-final section "
2303 "%d\n", i_sectionId);
2304 break;
2305 }
2306 xipSetImageSize(io_image, section.iv_offset + section.iv_size);
2307 }
2308
2309
2310 // Make sure the allocated space won't overflow. Set the return
2311 // parameter o_sectionOffset and copy the new data into the image (or
2312 // simply clear the space).
2313
2314 if ((xipImageSize(io_image) + i_size) > i_allocation) {
2315 rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW);
2316 break;
2317 }
2318 if (o_sectionOffset != 0) {
2319 *o_sectionOffset = section.iv_size;
2320 }
2321
2322 hostAddress =
2323 xipHostAddressFromOffset(io_image, xipImageSize(io_image));
2324 if (i_data == 0) {
2325 memset(hostAddress, 0, i_size);
2326 } else {
2327 memcpy(hostAddress, i_data, i_size);
2328 }
2329
2330
2331 // Update the image size and section table. Note that the final
2332 // alignment may push out of the allocation.
2333
2334 xipSetImageSize(io_image, xipImageSize(io_image) + i_size);
2335 xipFinalAlignment(io_image);
2336
2337 if (xipImageSize(io_image) > i_allocation) {
2338 rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW);
2339 break;
2340 }
2341
2342 section.iv_size += i_size;
2343
2344 if (xipPutSection(io_image, i_sectionId, §ion) != 0) {
2345 rc = TRACE_ERROR(SBE_XIP_BUG); /* Can't happen */
2346 break;
2347 }
2348
2349
2350 // Special case
2351
2352 if (i_sectionId == SBE_XIP_SECTION_TOC) {
2353 ((SbeXipHeader*)io_image)->iv_tocSorted = 0;
2354 }
2355
2356 } while (0);
2357
2358 if (rc && restoreOnError) {
2359 if (xipPutSection(io_image, i_sectionId, &initialSection) != 0) {
2360 rc = TRACE_ERROR(SBE_XIP_BUG); /* Can't happen */
2361 }
2362 xipSetImageSize(io_image, initialSize);
2363 }
2364
2365 return rc;
2366 }
2367
2368
2369 int
sbe_xip_section2pore(const void * i_image,const int i_sectionId,const uint32_t i_offset,uint64_t * o_poreAddress)2370 sbe_xip_section2pore(const void* i_image,
2371 const int i_sectionId,
2372 const uint32_t i_offset,
2373 uint64_t* o_poreAddress)
2374 {
2375 int rc;
2376 SbeXipSection section;
2377
2378 do {
2379 rc = xipQuickCheck(i_image, 0);
2380 if (rc) break;
2381
2382 rc = sbe_xip_get_section(i_image, i_sectionId, §ion);
2383 if (rc) break;
2384
2385 if (section.iv_size == 0) {
2386 rc = TRACE_ERROR(SBE_XIP_SECTION_ERROR);
2387 break;
2388 }
2389
2390 if (i_offset > (section.iv_offset + section.iv_size)) {
2391 rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
2392 break;
2393 }
2394
2395 *o_poreAddress = xipLinkAddress(i_image) + section.iv_offset + i_offset;
2396
2397 if (*o_poreAddress % 4) {
2398 rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
2399 break;
2400 }
2401
2402 } while(0);
2403
2404 return rc;
2405 }
2406
2407
2408 int
sbe_xip_pore2section(const void * i_image,const uint64_t i_poreAddress,int * i_section,uint32_t * i_offset)2409 sbe_xip_pore2section(const void* i_image,
2410 const uint64_t i_poreAddress,
2411 int* i_section,
2412 uint32_t* i_offset)
2413 {
2414 int rc;
2415
2416 do {
2417 rc = xipQuickCheck(i_image, 0);
2418 if (rc) break;
2419
2420 rc = xipPore2Section(i_image, i_poreAddress, i_section, i_offset);
2421
2422 } while(0);
2423
2424 return rc;
2425 }
2426
2427
2428 int
sbe_xip_pore2host(const void * i_image,const uint64_t i_poreAddress,void ** o_hostAddress)2429 sbe_xip_pore2host(const void* i_image,
2430 const uint64_t i_poreAddress,
2431 void** o_hostAddress)
2432 {
2433 int rc;
2434
2435 do {
2436 rc = xipQuickCheck(i_image, 0);
2437 if (rc) break;
2438
2439 if ((i_poreAddress < xipLinkAddress(i_image)) ||
2440 (i_poreAddress >
2441 (xipLinkAddress(i_image) + xipImageSize(i_image)))) {
2442 rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
2443 break;
2444 }
2445
2446 *o_hostAddress =
2447 xipHostAddressFromOffset(i_image,
2448 i_poreAddress - xipLinkAddress(i_image));
2449 } while(0);
2450
2451 return rc;
2452 }
2453
2454
2455 int
sbe_xip_host2pore(const void * i_image,void * i_hostAddress,uint64_t * o_poreAddress)2456 sbe_xip_host2pore(const void* i_image,
2457 void* i_hostAddress,
2458 uint64_t* o_poreAddress)
2459 {
2460 int rc;
2461
2462 do {
2463 rc = xipQuickCheck(i_image, 0);
2464 if (rc) break;
2465
2466 if ((i_hostAddress < i_image) ||
2467 (i_hostAddress >
2468 xipHostAddressFromOffset(i_image, xipImageSize(i_image)))) {
2469 rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
2470 break;
2471 }
2472
2473 *o_poreAddress = xipLinkAddress(i_image) +
2474 ((unsigned long)i_hostAddress - (unsigned long)i_image);
2475 if (*o_poreAddress % 4) {
2476 rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
2477 break;
2478 }
2479 } while(0);
2480
2481 return rc;
2482 }
2483
2484
2485 void
sbe_xip_translate_header(SbeXipHeader * o_dest,const SbeXipHeader * i_src)2486 sbe_xip_translate_header(SbeXipHeader* o_dest, const SbeXipHeader* i_src)
2487 {
2488 #ifndef _BIG_ENDIAN
2489 int i;
2490 SbeXipSection* destSection;
2491 const SbeXipSection* srcSection;
2492
2493 #if SBE_XIP_HEADER_VERSION != 8
2494 #error This code assumes the SBE-XIP header version 8 layout
2495 #endif
2496
2497 o_dest->iv_magic = xipRevLe64(i_src->iv_magic);
2498 o_dest->iv_entryOffset = xipRevLe64(i_src->iv_entryOffset);
2499 o_dest->iv_linkAddress = xipRevLe64(i_src->iv_linkAddress);
2500 o_dest->iv_ptsVersion = xipRevLe64(i_src->iv_ptsVersion);
2501
2502 for (i = 0; i < 4; i++) {
2503 o_dest->iv_reserved64[i] = 0;
2504 }
2505
2506 for (i = 0, destSection = o_dest->iv_section,
2507 srcSection = i_src->iv_section;
2508 i < SBE_XIP_SECTIONS;
2509 i++, destSection++, srcSection++) {
2510 xipTranslateSection(destSection, srcSection);
2511 }
2512
2513 o_dest->iv_imageSize = xipRevLe32(i_src->iv_imageSize);
2514 o_dest->iv_buildDate = xipRevLe32(i_src->iv_buildDate);
2515 o_dest->iv_buildTime = xipRevLe32(i_src->iv_buildTime);
2516
2517 for (i = 0; i < 5; i++) {
2518 o_dest->iv_reserved32[i] = 0;
2519 }
2520
2521 o_dest->iv_headerVersion = i_src->iv_headerVersion;
2522 o_dest->iv_normalized = i_src->iv_normalized;
2523 o_dest->iv_tocSorted = i_src->iv_tocSorted;
2524
2525 for (i = 0; i < 3; i++) {
2526 o_dest->iv_reserved8[i] = 0;
2527 }
2528
2529 memcpy(o_dest->iv_buildUser, i_src->iv_buildUser,
2530 sizeof(i_src->iv_buildUser));
2531 memcpy(o_dest->iv_buildHost, i_src->iv_buildHost,
2532 sizeof(i_src->iv_buildHost));
2533 memcpy(o_dest->iv_reservedChar, i_src->iv_reservedChar,
2534 sizeof(i_src->iv_reservedChar));
2535
2536 #else
2537 if (o_dest != i_src) {
2538 *o_dest = *i_src;
2539 }
2540 #endif /* _BIG_ENDIAN */
2541 }
2542
2543
2544 int
sbe_xip_map_toc(void * io_image,int (* i_fn)(void * io_image,const SbeXipItem * i_item,void * io_arg),void * io_arg)2545 sbe_xip_map_toc(void* io_image,
2546 int (*i_fn)(void* io_image,
2547 const SbeXipItem* i_item,
2548 void* io_arg),
2549 void* io_arg)
2550 {
2551 int rc;
2552 SbeXipToc *imageToc;
2553 SbeXipItem item;
2554 size_t entries;
2555
2556 do {
2557 rc = xipQuickCheck(io_image, 0);
2558 if (rc) break;
2559
2560 rc = xipGetToc(io_image, &imageToc, &entries, 0, 0);
2561 if (rc) break;
2562
2563 for (; entries--; imageToc++) {
2564 rc = xipDecodeToc(io_image, imageToc, &item);
2565 if (rc) break;
2566 rc = i_fn(io_image, &item, io_arg);
2567 if (rc) break;
2568 }
2569 } while(0);
2570
2571 return rc;
2572 }
2573