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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion);
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, §ion) != 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, §ion);
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