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