Subversion Repositories QNX 8.QNX8 IFS tool

Rev

Rev 26 | Rev 31 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 26 Rev 30
Line 134... Line 134...
134
static uint32_t image_align = 4; // default image alignment, as per QNX docs
134
static uint32_t image_align = 4; // default image alignment, as per QNX docs
135
static uint32_t image_kernel_ino = 0;
135
static uint32_t image_kernel_ino = 0;
136
static uint32_t image_bootscript_ino = 0;
136
static uint32_t image_bootscript_ino = 0;
137
static int startup_header_compression_flag = STARTUP_HDR_FLAGS1_COMPRESS_NONE;
137
static int startup_header_compression_flag = STARTUP_HDR_FLAGS1_COMPRESS_NONE;
138
#if defined(__x86_64__)
138
#if defined(__x86_64__)
139
static char image_processor[16] = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
139
static char *image_processor = "x86_64"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
140
static char image_processor_base[16] = "x86_64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
140
static char *image_processor_base = "x86_64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
-
 
141
static size_t image_pagesize = 4 * 1024; // default page size for the image, depends on the CPU type. Intel has 4kb pages, ARM has 16kb ones.
141
#elif defined(__aarch64__)
142
#elif defined(__aarch64__)
142
static char image_processor[16] = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
143
static char *image_processor = "aarch64le"; // default CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
143
static char image_processor_base[16] = "aarch64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
144
static char *image_processor_base = "aarch64"; // default base CPU type for which this image is built, either "x86_64" or "aarch64le" (will be used to find out the right include paths under $QNX_TARGET)
-
 
145
static size_t image_pagesize = 16 * 1024; // default page size for the image, depends on the CPU type. Intel has 4kb pages, ARM has 16kb ones.
144
#else // unknown platform
146
#else // unknown platform
145
#error Please port ifstool to this platform
147
#error Please port ifstool to this platform
146
#endif
148
#endif
147
static char *buildfile_pathname = NULL; // pathname of IFS build file
149
static char *buildfile_pathname = NULL; // pathname of IFS build file
148
static char *current_line = NULL; // copy of current line in IFS build file
150
static char *current_line = NULL; // copy of current line in IFS build file
Line 156... Line 158...
156
// bootable IFS support
158
// bootable IFS support
157
static char *bootfile_pathname = NULL;           // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
159
static char *bootfile_pathname = NULL;           // FIXME: HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
158
static size_t bootfile_size = 0;                 // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
160
static size_t bootfile_size = 0;                 // FIXME: HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
159
static char *startupfile_pathname = NULL;        // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
161
static char *startupfile_pathname = NULL;        // FIXME: HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
160
static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS 
162
static size_t startupfile_ep_from_imagebase = 0; // FIXME: HACK: startup code entrypoint offset from image base for a bootable IFS 
161
static size_t kernelfile_offset = 0x32000;       // kernel file offset in the IFS (is it ever supposed to change?)
163
static size_t kernelfile_offset = 0;             // kernel file offset in the IFS (first offset rounded at pagesize after the dirents table)
162
 
164
 
163
 
165
 
164
// exported function prototypes
166
// exported function prototypes
165
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer
167
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer
166
 
168
 
Line 635... Line 637...
635
   size_t size_in_file;
637
   size_t size_in_file;
636
   size_t file_offset;
638
   size_t file_offset;
637
   size_t array_index;
639
   size_t array_index;
638
   size_t table_index;
640
   size_t table_index;
639
   size_t table_count;
641
   size_t table_count;
640
   size_t page_size;
-
 
641
 
-
 
642
   // find out the platform page size
-
 
643
   if (ELF_GET_NUMERIC (ELFHDR, ELFHDR, instruction_set) == ELF_MACHINE_X86_64)
-
 
644
      page_size = 4 * 1024; // 4 kb pages on Intel processors
-
 
645
   else if (ELF_GET_NUMERIC (ELFHDR, ELFHDR, instruction_set) == ELF_MACHINE_AARCH64)
-
 
646
      page_size = 16 * 1024; // 16 kb pages on ARM64
-
 
647
   else
-
 
648
   {
-
 
649
      errno = ENOTSUP; // unsupported architecture: set errno to something meaningful
-
 
650
      return (0); // and return an error value
-
 
651
   }
-
 
652
 
642
 
653
   // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first
643
   // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first
654
   table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers
644
   table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers
655
   for (table_index = 0; table_index < table_count; table_index++)
645
   for (table_index = 0; table_index < table_count; table_index++)
656
   {
646
   {
Line 703... Line 693...
703
      if (ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory) > new_shdrtable_offset_method2)
693
      if (ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory) > new_shdrtable_offset_method2)
704
         new_shdrtable_offset_method2 = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory);
694
         new_shdrtable_offset_method2 = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory);
705
   }
695
   }
706
   if (new_shdrtable_offset_method2 > new_shdrtable_offset)
696
   if (new_shdrtable_offset_method2 > new_shdrtable_offset)
707
      LOG_DEBUG ("METHOD2: %llx > %llx", new_shdrtable_offset_method2, new_shdrtable_offset);*/
697
      LOG_DEBUG ("METHOD2: %llx > %llx", new_shdrtable_offset_method2, new_shdrtable_offset);*/
708
   //new_shdrtable_offset = ROUND_TO_UPPER_MULTIPLE (new_shdrtable_offset, page_size); // round to page size
698
   //new_shdrtable_offset = ROUND_TO_UPPER_MULTIPLE (new_shdrtable_offset, image_pagesize); // round to page size
709
 
699
 
710
   // re-create the section header table
700
   // re-create the section header table
711
   ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table
701
   ADD_SECTION (".shstrtab", &elf_section); // the first section will be the section names strings table
712
   ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table
702
   ASSERT_WITH_ERRNO (Buffer_InitWithByteArray (&elf_section->data, "\0")); // initialize an empty section headers strings table
713
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator
703
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&elf_section->data, ".shstrtab\0")); // append ".shstrtab" *INCLUDING* its null terminator
Line 766... Line 756...
766
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset);
756
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_offset, new_shdrtable_offset);
767
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, new_shdrtable_len);
757
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_table_len, new_shdrtable_len);
768
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section
758
   ELF_SET_NUMERIC (ELFHDR, ELFHDR, section_header_names_idx, elf_section_count); // the section headers strings table is the last section
769
 
759
 
770
   // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space
760
   // align size with page size (4096 on x86, 16k on ARM), zerofilling the extra space
771
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, page_size)));
761
   ASSERT_WITH_ERRNO (Buffer_PadWithZeroesTo (file, ROUND_TO_UPPER_MULTIPLE (file->size, image_pagesize)));
772
 
762
 
773
   // cleanup
763
   // cleanup
774
   for (table_index = 0; table_index < elf_section_count; table_index++)
764
   for (table_index = 0; table_index < elf_section_count; table_index++)
775
      Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers
765
      Buffer_Forget (&elf_sections[table_index].data); // free all sections' backing buffers
776
 
766
 
Line 1757... Line 1747...
1757
            if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them
1747
            if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // FIXME: HACK until I figure out how to re-create them
1758
               DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
1748
               DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile and --startupfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
1759
            if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
1749
            if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
1760
            {
1750
            {
1761
               *sep = 0;
1751
               *sep = 0;
-
 
1752
               if (strcmp (value, "x86_64") == 0)
-
 
1753
               {
-
 
1754
                  image_processor = "x86_64"; // save processor
-
 
1755
                  image_processor_base = "x86_64"; // save processor base
-
 
1756
                  image_pagesize = 4 * 1024; // Intel processors use 4 Kb pages
-
 
1757
               }
-
 
1758
               else if (strcmp (value, "aarch64le") == 0)
-
 
1759
               {
1762
               strcpy_s (image_processor, sizeof (image_processor), value); // save processor
1760
                  image_processor = "aarch64le"; // save processor
-
 
1761
                  image_processor_base = "aarch64"; // save processor base
-
 
1762
                  image_pagesize = 16 * 1024; // ARM processors use 16 Kb pages
-
 
1763
               }
-
 
1764
               else
-
 
1765
                  DIE_WITH_EXITCODE (1, "unrecognized processor type in 'virtual' attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, value);
1763
               value = sep + 1;
1766
               value = sep + 1;
1764
            }
1767
            }
1765
            if (stat (bootfile_pathname, &stat_buf) != 0)
1768
            if (stat (bootfile_pathname, &stat_buf) != 0)
1766
               DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
1769
               DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
1767
            bootfile_size = stat_buf.st_size; // save preboot file size
1770
            bootfile_size = stat_buf.st_size; // save preboot file size
Line 1905... Line 1908...
1905
            else
1908
            else
1906
            {
1909
            {
1907
               is_escaped_char = false; // any other char, meaning the next one will not be escaped
1910
               is_escaped_char = false; // any other char, meaning the next one will not be escaped
1908
               if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet
1911
               if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet
1909
               {
1912
               {
1910
                  if (entry_parms.data.size == allocated_size) // reallocate in 4 kb blocks
1913
                  if (entry_parms.data.size == allocated_size) // reallocate in 16k blocks
1911
                  {
1914
                  {
1912
                     reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 4096);
1915
                     reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 16384);
1913
                     ASSERT_WITH_ERRNO (reallocated_ptr);
1916
                     ASSERT_WITH_ERRNO (reallocated_ptr);
1914
                     entry_parms.data.bytes = reallocated_ptr;
1917
                     entry_parms.data.bytes = reallocated_ptr;
1915
                     allocated_size += 4096;
1918
                     allocated_size += 16384;
1916
                  }
1919
                  }
1917
                  entry_parms.data.bytes[entry_parms.data.size++] = read_char;
1920
                  entry_parms.data.bytes[entry_parms.data.size++] = read_char;
1918
               }
1921
               }
1919
               if (read_char == '\n')
1922
               if (read_char == '\n')
1920
                  lineno++; // update line counter as we parse the inline content
1923
                  lineno++; // update line counter as we parse the inline content
Line 2392... Line 2395...
2392
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2395
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2393
 
2396
 
2394
   // is it a bootable image with a startup file ?
2397
   // is it a bootable image with a startup file ?
2395
   if (startupfile_pathname != NULL)
2398
   if (startupfile_pathname != NULL)
2396
   {
2399
   {
-
 
2400
      // compute the kernel offset: address of the first page that comes after the directory entries
-
 
2401
      kernelfile_offset = ROUND_TO_UPPER_MULTIPLE (ifs.data.size, image_pagesize);
-
 
2402
 
2397
      // write the filesystem entries that may fit before the kernel
2403
      // write the filesystem entries that may fit before the kernel
2398
      for (;;)
2404
      for (;;)
2399
      {
2405
      {
2400
         available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel
2406
         available_space = kernelfile_offset - ifs.data.size; // measure the available space until the kernel
2401
 
2407
 
Line 2541... Line 2547...
2541
         if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL)
2547
         if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_UCL)
2542
         {
2548
         {
2543
            // UCL compression. NOTE: the decompressor function used in startup-x86 is "ucl_nrv2b_decompress_8". Also compression level is hardcoded at 9 in mkifs, but can range from 1 to 10
2549
            // UCL compression. NOTE: the decompressor function used in startup-x86 is "ucl_nrv2b_decompress_8". Also compression level is hardcoded at 9 in mkifs, but can range from 1 to 10
2544
            static ucl_uint ucl_outlen; // have a different variable because of pointer size mismatch
2550
            static ucl_uint ucl_outlen; // have a different variable because of pointer size mismatch
2545
            while (((compressor_ret = ucl_nrv2b_99_compress (compressor_in, (ucl_uint) compressor_inlen, compressor_out, &ucl_outlen, NULL, 9, NULL, NULL)) == UCL_E_OK) && (ucl_outlen > 0xFFFF))
2551
            while (((compressor_ret = ucl_nrv2b_99_compress (compressor_in, (ucl_uint) compressor_inlen, compressor_out, &ucl_outlen, NULL, 9, NULL, NULL)) == UCL_E_OK) && (ucl_outlen > 0xFFFF))
2546
               compressor_inlen -= 4096; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with 4kb input less
2552
               compressor_inlen -= image_pagesize; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with one page input less
2547
            ASSERT (compressor_ret == UCL_E_OK, "UCL compression error: ucl_nrv2b_99_compress() returned %d", compressor_ret); // make sure it's not a compression error
2553
            ASSERT (compressor_ret == UCL_E_OK, "UCL compression error: ucl_nrv2b_99_compress() returned %d", compressor_ret); // make sure it's not a compression error
2548
            compressor_outlen = ucl_outlen; // cast back to size_t
2554
            compressor_outlen = ucl_outlen; // cast back to size_t
2549
         }
2555
         }
2550
         else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO)
2556
         else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_LZO)
2551
         {
2557
         {
2552
            // LZO compression. NOTE: the compressor function used in mkifs is "lzo1x_999_compress" which is from the full LZO package... I use use minilzo, but I have to admit the compression ratio of the full LZO is *much* better.
2558
            // LZO compression. NOTE: the compressor function used in mkifs is "lzo1x_999_compress" which is from the full LZO package... I use use minilzo, but I have to admit the compression ratio of the full LZO is *much* better.
2553
            static lzo_align_t lzo_workmem[(LZO1X_1_MEM_COMPRESS + (sizeof (lzo_align_t) - 1)) / sizeof(lzo_align_t)]; // heap-allocated aligned buffer
2559
            static lzo_align_t lzo_workmem[(LZO1X_1_MEM_COMPRESS + (sizeof (lzo_align_t) - 1)) / sizeof(lzo_align_t)]; // heap-allocated aligned buffer
2554
            static lzo_uint lzo_outlen; // have a different variable because of pointer size mismatch
2560
            static lzo_uint lzo_outlen; // have a different variable because of pointer size mismatch
2555
            while (((compressor_ret = lzo1x_1_compress (compressor_in, compressor_inlen, compressor_out, &lzo_outlen, lzo_workmem)) == UCL_E_OK) && (lzo_outlen > 0xFFFF))
2561
            while (((compressor_ret = lzo1x_1_compress (compressor_in, compressor_inlen, compressor_out, &lzo_outlen, lzo_workmem)) == UCL_E_OK) && (lzo_outlen > 0xFFFF))
2556
               compressor_inlen -= 4096; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with 4kb input less
2562
               compressor_inlen -= image_pagesize; // as long as we can't produce compressed blocks whose size can fit in 2 bytes, try again with one page input less
2557
            ASSERT (compressor_ret == LZO_E_OK, "LZO compression error: lzo1x_1_compress() returned %d", compressor_ret); // make sure it's not a compression error
2563
            ASSERT (compressor_ret == LZO_E_OK, "LZO compression error: lzo1x_1_compress() returned %d", compressor_ret); // make sure it's not a compression error
2558
            compressor_outlen = lzo_outlen; // cast back to size_t
2564
            compressor_outlen = lzo_outlen; // cast back to size_t
2559
         }
2565
         }
2560
         else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB)
2566
         else if (startup_header_compression_flag == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB)
2561
         {
2567
         {
2562
            // Zlib (TODO)
2568
            // Zlib (TODO)
2563
         }
2569
         }
2564
 
2570
 
2565
         // the compression produced a block smaller than 65536 bytes
2571
         // the compression produced a block smaller than 65536 bytes
2566
         LOG_DEBUG ("compressed block size %zd", compressor_outlen);
2572
         //LOG_DEBUG ("compressed block size %zd", compressor_outlen);
2567
         compressed_imagefs.bytes[compressed_imagefs.size + 0] = (uint8_t) (compressor_outlen >> 8); // write compressed block size word (in big endian)
2573
         compressed_imagefs.bytes[compressed_imagefs.size + 0] = (uint8_t) (compressor_outlen >> 8); // write compressed block size word (in big endian)
2568
         compressed_imagefs.bytes[compressed_imagefs.size + 1] = (uint8_t) (compressor_outlen >> 0);
2574
         compressed_imagefs.bytes[compressed_imagefs.size + 1] = (uint8_t) (compressor_outlen >> 0);
2569
         compressed_imagefs.size += 2 + (size_t) compressor_outlen; // advance in compression buffer by the compressed block size word plus the compressed block size
2575
         compressed_imagefs.size += 2 + (size_t) compressor_outlen; // advance in compression buffer by the compressed block size word plus the compressed block size
2570
 
2576
 
2571
         remaining_len -= compressor_inlen; // see how many bytes remain to compress
2577
         remaining_len -= compressor_inlen; // see how many bytes remain to compress