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, &section);
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, &section);
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, &section);
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, &section);
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, &section);
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, &section);
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, &section);
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, &section);
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, &section);
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, &section);
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, &section) != 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, &section);
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